我有方面(见下文),它应该记录db中的操作(创建,更新,删除)。取决于在preProcess或postProcess方法中发生的操作日志记录。如果通过这些操作发生一些失败,我不应该记录任何事情。即如果创建没有发生,那么就没有必要记录它。
我试过测试它。我在连接点抛出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:
@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) {}
}
由aspcet拦截的类:
@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);
}
}
可记录注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
LoggingMessages value();
Class<? extends LoggingStrategy> strategy();
}
记录更新操作包含: id,created_dtm,action(DEVICE_UPDATE),device_data_before_action_on_the_device(以json格式),device_data_after_action_on_the_device(以json格式),created_by。
答案 0 :(得分:0)
免责声明: 其实我不是Spring专家,也许其他人可以帮助你。我的专业领域是AspectJ,这就是我发现你的问题的方式。
无论如何,你有两个问题:
@Transactional
注释LoggingAspect.saveActionMessage(..)
。实际上我根本不知道这是否有效(我发现在网络上的方面方法/建议上没有使用@Transactional
的例子,但也许我用错误的方式搜索)因为Spring中的声明式事务处理是通过代理实现的基于Spring AOP的技术。请阅读Spring手册中的chapter 12 about transaction management以获取更多详细信息,尤其是chapter 12.5.1。我很确定你会找到一种方法来做你想做的事。
UpdateProcessStrategy.preProcess(..)
被称为事务性的建议调用,但也被声明为@Transactional
。所以你在交易中有一个交易。 Spring如何处理这个问题,我不知道,但也许这个tutorial about Spring transaction propagation包含启发性的细节。 Spring手册列出了几种实现事务行为的方法:以编程方式,通过注释声明性地,基于XML的<tx:advice>
内容等等。我不知道哪种方式最适合你,我只是想提供一些一般的提示。