Donnerstag, August 03, 2006

Using Spring 2.0's @Configurable Annotation with Compile-Time Weaving

It will not take long that Spring 2.0 (final) will be released. One of the new features of Spring 2.0 is the @Configurable annotation. In essence, it allows you to perform dependency injection for beans created by plain constructor calls. Spring will intercept the constructor call and do the dependency injection for you.

People already blog about it. It is already quite well documented. So, let's start with some code:


package at.mitterdorfer.blog;

import org.springframework.beans.factory.annotation;

@Configurable
public class MySuperBean {
private Foo foo;

public MySuperBean() {
}

//Spring will invoke this method
//after somebody calls new MySuperBean();
public void setFoo(Foo foo) {
this.foo = foo;
}
}


Next, there's your Application Context file:


...
<!-- ensure the AnnotationBeanConfigurerAspect
gets configured by Spring -->
<aop:spring-configured/>

<bean id="foo" class="at.mitterdorfer.blog.Foo"/>

<bean class="at.mitterdorfer.blog.MySuperBean">
<property name="foo" ref="foo"/>
</bean>
...


Note that you have to use the new Schema based configuration for your application context file. For a more detailed introduction about @Configurable and its configuration in the application context file, please refer to the Spring reference documentation.

As this feature uses AspectJ, the respective aspect has to be woven at some time. This can either happen at compile-time or at load-time. Loadtime weaving is well documented in the Spring reference documentation. However, I disliked the approach to set the VM argument "-javaagent" in order to perform load-time weaving. Therefore, I decided to use compile-time weaving.

As I use Maven2 as my build tool I searched a plugin that invokes the AspectJ compiler for me. Although such a plugin exists, there is no official release yet. So I checked it out from the Subversion repository (svn://svn.codehaus.org/mojo/trunk/mojo/aspectj-maven-plugin). Afterwards, I built and installed the plugin:

mvn package install

Well, the build went not that smooth. You may face problems regarding corrupt aspectj libraries. I finally downloaded the 1.5.2 release from the AspectJ project homepage and installed the JARs manually to my local Maven2 repository. Next, some testcases failed. I have ignored them and moved on. Next, you have to adapt project's POM. Configure it as follows:


<plugin>
<groupid>org.codehaus.mojo</groupid>
<artifactid>aspectj-maven-plugin</artifactid>
<version>1.0-beta-2-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<!--compile for JDK 1.5 -->
<source>1.5</source>
<target>1.5</target>
<verbose>false</verbose>
<showweaveinfo>true</showweaveinfo>
<!-- tell the AspectJ compiler where to find the aspects -->
<aspectlibraries>
<aspectlibrary>
<groupid>org.springframework</groupid>
<artifactid>spring-aspects</artifactid>
</aspectlibrary>
</aspectlibraries>
</configuration>
</plugin>


Unfortunately, the plugin seems to ignore that verbose is set to false and will is quite verbose when it compiles the code. Note that this plugin does not complement, but substitutes the maven-compiler-plugin!

Note that you have to include aspectjtools-1.5.2, aspectjrt-1.5.2, aspectjweaver-1.5.2 and of course spring-aspects in your dependencies:

<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-aspects</artifactid>
<version>2.0-m4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>aspectj</groupid>
<artifactid>aspectjweaver</artifactid>
<version>1.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>aspectj</groupid>
<artifactid>aspectjrt</artifactid>
<version>1.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>aspectj</groupid>
<artifactid>aspectjtools</artifactid>
<version>1.5.2</version>
<scope>compile</scope>
</dependency>

spring-aspects is needed as it contains the actual aspect for the @Configurable annotation which has to be woven with your classes during compilation (you can see the weaving info after the classes have been compiled if you enable showWeaveInfo as shown above). After you have adapted your project's POM accordingly you can build your application using Maven 2 and your @Configurable annotated SuperBean gets its dependencies properly injected by Spring.