I've created an Aspect which contains an @Transactional annotation. My advice is being invoked as expected, but the new entity AuditRecord is never saved to the database, it looks like my @Transactional annotation is not working.
@Aspect
@Order(100)
public class ServiceAuditTrail {
private AppService appService;
private FooRecordRepository fooRecordRepository;
@AfterReturning("execution(* *.app.services.*.*(..))")
public void logAuditTrail(JoinPoint jp){
Object[] signatureArgs = jp.getArgs();
String methodName = jp.getSignature().getName();
List<String> args = new ArrayList<String>();
for(Object arg : signatureArgs){
args.add(arg.toString());
}
createRecord(methodName, args);
}
@Transactional
private void createRecord(String methodName, List<String> args){
AuditRecord auditRecord = new AuditRecord();
auditRecord.setDate(new Date());
auditRecord.setAction(methodName);
auditRecord.setDetails(StringUtils.join(args, ";"));
auditRecord.setUser(appService.getUser());
fooRecordRepository.addAuditRecord(auditRecord);
}
public void setAppService(AppService appService) {
this.appService = appService;
}
public void setFooRecordRepository(FooRecordRepository fooRecordRepository) {
this.fooRecordRepository= fooRecordRepository;
}
}
The bean context is as follows:
<tx:annotation-driven transaction-manager="txManager.main" order="200"/>
<aop:aspectj-autoproxy />
<bean id="app.aspect.auditTrail" class="kernel.audit.ServiceAuditTrail">
<property name="appService" ref="app.service.generic" />
<property name="fooRecordRepository" ref="domain.repository.auditRecord" />
</bean>
My pointcut is intercepting only interfaces (service interfaces). The service methods may or may not be transactional. If the service method is transactional, I would like that transaction to be rolled back if the Advice fails for some reason.
My question: Why is the transactional annotation being ignored? This is my first time building an AOP service with Spring, I would also welcome any architectural or implementation improvements.
Thanks!
The Transactional Aspect is an 'around' aspect that gets called both before and after the annotated business method. The concrete class for implementing the aspect is TransactionInterceptor .
The combination of AOP with transactional metadata yields an AOP proxy that uses a TransactionInterceptor in conjunction with an appropriate PlatformTransactionManager implementation to drive transactions around method invocations.
The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.
The usage of the @Repository annotation or @Transactional . @Repository is not needed at all as the interface you declare will be backed by a proxy the Spring Data infrastructure creates and activates exception translation for anyway.
In Spring, @Transactional
works by creating a proxy of your class (either a Java or cglib proxy) and intercepting the annotated method. This means that @Transactional
doesn't work if you are calling the annotated method from another method of the same class.
Just move the createRecord
method to a new class (don't forget to make it a Spring bean too) and it will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With