spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

No well-defined advice order for @Transactional and @Async in AspectJ mode

Open kklepacz opened this issue 6 years ago • 1 comments

Affects: 5.x.x


Since Spring 5 (spring-aspects 5.x.x), it looks like @Transactional is ignored on the method with @Async when using AdviceMode.ASPECTJ for both @EnableTransactionManagement and @EnableAsync.

Please take a look on following demo: https://github.com/kklepacz/spring-async-transaction-demo

After running mvn clean test you should see following output:

2020-01-07 12:02:50.729  INFO 29454 --- [ async-thread-1] c.e.asynctransactiondemo.AsyncListener   : Transaction in async listener? false

So even if @Transactional annotation is present on handle method, transaction is not active.

Now, let's change Spring version. Update pom to use Spring 4 + Spring Boot 1.5.x

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.22.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

Run mvn clean test again. Output:

2020-01-07 12:06:38.082 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.asynctransactiondemo.AsyncListener.handle]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-01-07 12:06:38.082 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8] for JPA transaction
2020-01-07 12:06:38.083 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@350a70f1]
2020-01-07 12:06:38.083  INFO 29675 --- [ async-thread-1] c.e.asynctransactiondemo.AsyncListener   : Transaction in async listener? true
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8]
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8] after transaction

Transaction is active.

Is it a bug or a feature and I need some extra configuration to have my Spring Boot 2 version working as expected?

Is it related to AJC compilation anyhow? I can see a difference between an order of compilation in maven output. For Spring Aspects 5.x:

[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect' (spring-aspects-5.1.9.RELEASE.jar!AbstractAsyncExecutionAspect.class:65(from AbstractAsyncExecutionAspect.aj))
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (spring-aspects-5.1.9.RELEASE.jar!AbstractTransactionAspect.class:66(from AbstractTransactionAspect.aj))

For Spring Aspects 4.x - order is different:

[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (spring-aspects-4.3.25.RELEASE.jar!AbstractTransactionAspect.class:66(from AbstractTransactionAspect.aj))
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect' (spring-aspects-4.3.25.RELEASE.jar!AbstractAsyncExecutionAspect.class:65(from AbstractAsyncExecutionAspect.aj))

kklepacz avatar Jan 07 '20 11:01 kklepacz

According to the configuration of your demo project, I think you are using Compile-Time Weaving instead of LTW. But Spring project's aspects do not have advice ordering guaranteed( no precedence declaration in .aj file or precedence attribute in aop.xml).

Farteen avatar Jan 19 '20 22:01 Farteen