Java Chatter and Random Nagging

Tuesday, January 22, 2008

Ordering Spring Aspects

The order of application of Spring Aspects has kept me busy for a while. I think I finally figured them out, so let's share:

from the Spring manuals:
Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first). "On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. You can control the order of execution by specifying precedence. This is configured throught the Ordered interfacen, Order annotation or the configuration of order in xml. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.


As an example, using declarative transactions, suppose you have this:

<tx:annotation-driven transaction-manager="transactionManager" order="1"/>

I have a bean with transactional advice (propagation=REQUIRED)

<bean id="WorkYearApplicationService class="be.sunbeamsoftware.hammock.WorkYearApplicationService"/>

I have an aspect that is supposed to audit something in a database table, for a batch that will send e-mails later on.
The methods that need this are annotated with an @MailNotifiable.

<aop:pointcut id="supervisorActionPointCut"
expression="execution(* be.sunbeamsoftware.hammock.WorkYearApplicationService.*(..)) and @annotation(mailNotifiable) and args(employeeId, date, dayPart)" //>

<aop:aspect ref="actionAuditingAspect" order="3">
<aop:after-returning method="auditSupervisorActions"
pointcut-ref="supervisorActionPointCut"
arg-names="mailNotifiable, employeeId, date, dayPart" />
</aop:aspect>


This results in the following order of aspects :



Thus transactions are started first and committed last. This ordering is thanks to the lower order, thus higher precedence of the transaction aspect. It is also exactly what we want in this case.

Unfortunately (and the reason why this kept me busy), if you specify no order:

<tx:annotation-driven transaction-manager="transactionManager"/>

Then, by default the order of the declarative transactions is Integer.MAX_VALUE. This way, transactional advice is applied as the inner most aspect so our aspect for auditing something in the database after a call to WorkYearService, is not in the same transaction as the method of WorkYearService itself.

Explicitly setting the order property of the tx:annotation-driven will solve this. Just remember that the default transaction order in Spring is applying to the most inner level.

2 Comments:

At 10:51 pm, Anonymous Anonymous said...

Hello! Did you tried it with Spring 2.5? I get Validation Error (invalid stack size) when trying to use @Transactional and my aspect both under Spring 2.5. It seems that something wrong with CGLIB.
I'm running my application with spring-agent and Spring JUnit integration annotation.

 
At 4:31 pm, Blogger Ward said...

Yes, I did use Spring 2.5 to test this.

 

Post a Comment

<< Home