DB에서 작업 (생성, 업데이트, 삭제)을 기록해야하는 측면 (아래 참조)이 있습니다. preProcess 또는 postProcess 메소드에서 발생하는 조치 로깅에 따라 다름. 이 작업을 통해 어떤 실패가 발생하면 아무 것도 기록해서는 안됩니다. 나는. 생성이 발생하지 않았다면, 로깅 할 필요가 없습니다.트랜잭션이 aspectj에서 작동하지 않습니다
나는 그것을 시험해 보았다. 조인 시점에 RunTimeException을 던지고 db에 새로운 로그가 없다고 예상합니다. 불행히도 조인 포인트에서 예외가 발생하더라도 새 로그가 저장됩니다.
측면 :
@Component
@Aspect
public class LoggingAspect {
@Autowired
private ApplicationContext appContext;
@Autowired
private LoggingService loggingService;
@Around("@annotation(Loggable)")
@Transactional
public void saveActionMessage(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Loggable m = ms.getMethod().getAnnotation(Loggable.class);
LoggingStrategy strategy = appContext.getBean(m.strategy());
Object argument = joinPoint.getArgs()[0];
strategy.preProcess(argument);
joinPoint.proceed();
strategy.postProcess(argument);
}
}
TestApplicationConfig :
<context:spring-configured/>
<import resource="applicationConfig-common.xml"/>
<import resource="applicationConfig-security.xml"/>
<aop:aspectj-autoproxy/>
<util:map id="testValues">
<entry key="com.exadel.mbox.test.testSvnFile" value="${svnFolder.configPath}${svnRoot.file[0].fileName}"/>
<entry key="com.exadel.mbox.test.testCommonRepositoryPath" value="${svnRoot.commonRepositoryPath}"/>
<entry key="com.exadel.mbox.test.testMailFile" value="${mailingList.configPath}"/>
</util:map>
<context:component-scan base-package="com.exadel.report.common" />
<!-- Jpa Repositories -->
<jpa:repositories base-package="com.exadel.report.common.dao" />
<tx:annotation-driven proxy-target-class="true"
transaction-manager="txManager" mode="aspectj"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Data Source -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Entity Manager -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
</bean>
</property>
<property name="persistenceUnitName" value="exviewer-test"/>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
[업데이트]
LoggingStrategy :
public interface LoggingStrategy {
public void preProcess(Object obj);
public void postProcess(Object obj);
}
BaseLoggingStrategy :
는public class BaseLoggingStrategy implements LoggingStrategy {
@Override
public void preProcess(Object obj) {}
@Override
public void postProcess(Object obj) {}
}
UpdateProcessStrategy : aspcet에 의해 차단
@Service
public class UpdateProcessStrategy extends BaseLoggingStrategy {
@Autowired
private LoggingService loggingService;
@Autowired
private UserService userService;
@Autowired
DeviceService deviceService;
private Device currentDevice;
@Override
@Transactional
public void preProcess(Object obj) {
currentDevice = (Device) obj;
Device previousDevice = deviceService.getById(currentDevice.getId());
String deviceDataBeforeUpdate = deviceService.getDeviceDetailsInJSON(previousDevice);
String deviceDataAfterUpdate = deviceService.getDeviceDetailsInJSON(currentDevice);
String login = userService.getCurrentUser().getLogin();
String actionMessage = LoggingMessages.DEVICE_UPDATE.name();
loggingService.save(
new Logging(
login,
actionMessage,
deviceDataBeforeUpdate,
deviceDataAfterUpdate,
new Date())
);
}
@Override
public void postProcess(Object obj) {}
}
클래스 :
@Service
public class DeviceService {
@Loggable(value = LoggingMessages.DEVICE_CREATE, strategy = CreateProcessStrategy.class)
@Transactional
public void create(Device device) {
createOrUpdate(device);
}
@Loggable(value = LoggingMessages.DEVICE_UPDATE, strategy = UpdateProcessStrategy.class)
@Transactional
public void update(Device device) {
createOrUpdate(device);
}
private void createOrUpdate(Device device) {
deviceRepository.save(device);
}
@Loggable(value = LoggingMessages.DEVICE_REMOVE, strategy = RemoveProcessStrategy.class)
public void remove(Long deviceId) {
deviceRepository.delete(deviceId);
}
}
는
Loggable 주석 :
는@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
LoggingMessages value();
Class<? extends LoggingStrategy> strategy();
}
업데이트 작업에 대한 로그가 포함되어 id, created_dtm, 작업 (DEVICE_UPDATE), device_data_before_action_on_the_device (json 형식), device_data_after_action_on_the_device (json 형식), created_by.
'LoggingStrategy'에 대한 코드와 aspect에 의해 차단 된 대상 클래스를 게시하십시오. 그러면 전체 로그를 출력 할 수 있도록 로그 출력도 생성하십시오. 당신은 평범한 산문에서 중요한 부분들만을 설명하지만, 산문은 코드 없이는 분명히 이해하기에는 너무 모호합니다. 'Loggable' 주석 코드도 좋을 것입니다. – kriegaex
나는 언급 한 모든 것을 추가했습니다. – Vadzim
나는 여전히 문제를 이해하지 못한다 : 당신의 충고 내에서'proceed()'전에'preProcess() '를 호출한다. 그래서 joinpoint에서 실제 예외가 발생하기 전에 어떤 것이 기록된다는 것이 분명해야한다. 코드를 테스트하지 않아도 확인할 수 있습니다. 이를 변경하려면 일반적으로 로그인하는 방법이나 조언을 변경해야합니다. 그대로, 코드는 당신이 말하는대로합니다. 아니면 다른 문제가 있습니까? 기록 된 내용과 기록 할 내용에 대한 세부 정보는 아직 게시하지 않았습니다. – kriegaex