In this article we’ll see how to integrate your own aspects with Spring.
First we focus on load-time weaving using Spring’s dedicated AspectJ agents. Then we’ll see how to let Spring inject beans into your aspects
The below configuration is valid for Spring 3.0.5, Tomcat 6 & AspectJ 1.6.12
I Load-time weaving with Spring
A Spring configuration
To enable load-time weaving, we must add the <context:load-time-weaver> tag in the Spring XML configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> ... ... <context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/> ... ... </beans>
The weaver class org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver is applicable to Tomcat 6. If you are using another application server or servlet container, please refer to Spring official recommendation (table 7.1) here : Weaver Class configuration
You need to add extra Maven dependencies to your project’ pom.xml to get this class:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency>
spring-instrument-3.0.5.RELEASE.jar contains an Instrumentation agent needed at runtime and spring-aspects-3.0.5.RELEASE.jar contains aspects for Spring’s:
- @Transactional support
- @Configurable support
- JPA Exception translation support
- @Async annotation for scheduling support
B Tomcat configuration
Spring is shipped with a special AspectJ agent dedicated to Tomcat server. First you need to download the jar by adding this Maven dependency:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument-tomcat</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency>
Then put the spring-instrument-tomcat-3.0.5.RELEASE.jar file in the <Tomcat_Install>/lib folder.
Last but not least, add a custom class loader in Tomcat’ configuration for your web app:
<Context docBase="myAspectJApp" path="/myAspectJApp" reloadable="true" source="org.eclipse.jst.jee.server:myAspectJApp"> <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> </Context>
There is still one last configuration step to go.
C aop.xml
You need to create an aop.xml file and at it to the META-INF folder of your web app.
A sample aop.xml file:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver options="-verbose -showWeaveInfo -Xreweavable"> <include within="com.myApp..*"/> </weaver> <aspects> <concrete-aspect name="com.myApp.aspect.AspectPrecedence" precedence="com.myApp.aspect.metric.MetricsAspect,com.myApp.aspect.exception.ExceptionCatcherAspect" /> <aspect name="com.myApp.aspect.metric.MetricsAspect"/> <aspect name="com.myApp.aspect.exception.ExceptionCatcherAspect"/> </aspects> </aspectj>
Inside the <weaver> tag we declare all target classes to be woven with aspects by AspectJ. In the example, we restrict the classes to our application package to avoid AspectJ runtime to scan all classes on the classpath (very slow).
Inside the <aspects> tag we list all the aspects needed for the weaving process. You can also declare a concrete aspect to manage aspect precedence at this place.
You need not declare in the <aspects> section all Spring standard aspects (for @Transactional, @Configurable…). They are already declared in another aop.xml file in the spring-aspects-3.0.5.RELEASE.jar
<?xml version="1.0"?> <!-- AspectJ load-time weaving config file to install common Spring aspects. --> <aspectj> <!-- <weaver options="-showWeaveInfo"/> --> <aspects> <aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/> <aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/> <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/> </aspects> </aspectj>
II Spring’ aspects integration
To perform some business logic, your aspects may need to get a reference to a Spring managed bean. For this we can rely on dependency injection. However since the aspect instanciation and lifecycle is not managed by Spring but by AspectJ runtime, how can dependency be injected ?
The aspectOf() method comes to the rescue. Refer to Advanced AspectJ Part I : Instanciation model, chapter II Accessing the instance for more details on it.
By calling aspectOf() we can get the reference of the aspect instance. Dependency injection can be achieved by passing this instance to Spring.
<bean class="com.myApp.aspect.metric.MetricsAspect" factory-method="aspectOf"> <property name="myDao" ref="myDao"/> <property name="myEntityManagerFactory" ref="myEntityManagerFactory"/> </bean>
Of course this trick only works for aspect with singleton instanciation model. The other instanciation models need the target object as argument for aspectOf() (perthis, pertaget instanciations) or the control flow context (percflow, percflowbelow instantiations).
If your aspects are advising the same join points as Spring standard aspects (@Transactional for example) you can change your aspect precedence against Spring’ one.
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver options="-verbose -showWeaveInfo -Xreweavable"> <include within="com.myApp..*"/> </weaver> <aspects> <concrete-aspect name="com.myApp.aspect.AspectPrecedence" precedence="com.myApp.aspect.metric.MetricsAspect,org.springframework.transaction.aspectj.AnnotationTransactionAspect" /> <aspect name="com.myApp.aspect.metric.MetricsAspect"/> </aspects> </aspectj>
In the above example, the custom MetricsAspect aspect has been declared with higher precedence than Spring’ AnnotationTransactionAspect (@Transactional).
I personally really want to bookmark this specific article,
“Advanced AspectJ part V : integration with
Spring | DuyHai’s Java Blog” on my page. Will you care in the event I reallydo it? Thanks a lot ,Tonja
Please do so, no prob