There is still the urban myth that using Spring IoC container without thousands lines of XML code isn’t possible – so today we’re taking a look at annotation based configuration with Spring 3 and of course we’re using Maven..
Setup your project
-
Create a simple Maven project using
mvn archetype:generate // or mvn archetype:create
-
Add a lot of dependencies and reference them to the Spring version defined as a property in your pom.xml. A good reference on Spring 3 and Maven artifacts can be found at Springsource.com
<properties> <org.springframework.version>3.0.0.RELEASE</org.springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>com.springsource.org.aspectj.runtime</artifactId> <version>1.6.8.RELEASE</version> </dependency> </dependencies>
-
We are going to run the sample application using the Exec-Maven-Plugin so add the following markup to your pom.xml
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.hascode.tutorial.spring.Main</mainClass> </configuration> </plugin> </plugins> </build>
-
Last but not least we should adjust Maven’s compiler settings to use Java 5 because we’re going to use annotations
<properties> [..] <maven.compiler.source>5</maven.compiler.source> <maven.compiler.target>5</maven.compiler.target> </properties>
Setting up Spring 3
-
Create a file named application-context.xml in the directory src/main/resources
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config /> <context:component-scan base-package="com.hascode.tutorial.spring" /> <aop:aspectj-autoproxy /> </beans>
-
That’s all .. the rest is accomplished using annotations ..
Create the application
-
The Configuration Interface – PersonConfig
package com.hascode.tutorial.spring; public interface PersonConfig { public abstract String printName(); }
-
The Implementation – PersonConfigImpl
package com.hascode.tutorial.spring; import org.springframework.stereotype.Component; @Component public class PersonConfigImpl implements PersonConfig { /* * (non-Javadoc) * @see com.hascode.tutorial.spring.PersonConfig#printName() */ public String printName() { return "Mr. X"; } }
-
The Person Bean autowiring the needed PersonConfig class using the @autowired annotation
package com.hascode.tutorial.spring; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class Person { private PersonConfig personConfig; @Autowired public void setPersonConfig(PersonConfig personConfig) { this.personConfig = personConfig; } public String getName() { return personConfig.printName(); } }
-
The Main class that initializes the Spring Application Context
package com.hascode.tutorial.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "application-context.xml"); Person person = context.getBean(Person.class); System.out.println(person.getName()); } }
-
Now run the application and enjoy ;)
mvn clean compile exec:java
I don’t want no XML – Java Based Configuration
-
Use Guice – just kidding .. first define a configuration class using the @Configuration annotation
@Configuration public class ApplicationConfig { @Bean public TheBean theBean() { return new TheBeanImpl(); } }
-
Replace the application loading from XML file to loading from annotations in your Main class
ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
-
For detailed information take a look at the Spring documentation chapter 3.11 Java Based Container Configuration
Java EE 5 Common Annotations (JSR-250)
-
The following annotations from this standard are implemented:
-
@Resource: Has nearly the same meaning as @autowired
-
@PostConstruct and @PreDestroy: Lifecycle annotations used at object’s construction and destruction
-
Aspect Oriented Programming (AOP)
-
We’re just scratching the surface here – for deeper information take a look at the Spring documentation and the AspectJ Programming Guide
-
We’re creating a security interceptor that’s started when a method named getName is triggered using the @Aspect annotation
package com.hascode.tutorial.spring; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class SecurityAspect { @Pointcut("execution(* getName(..))") public void triggerSecurity() { } @Before("triggerSecurity()") public void process(JoinPoint joinPoint) { System.out.println("Checking security for: " + joinPoint.getSignature().getName()); } }
-
Enable the AspectJ autoproxy with this entry in your application-context.xml
<aop:aspectj-autoproxy/>
-
There is a helpful Maven plugin for the AspectJ part, the AspectJ Maven Plugin – add it to your pom.xml
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.8</version> </dependency> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.3</version> <executions> <execution> <goals> <goal>compile</goal> <!-- use this goal to weave all your main classes --> <goal>test-compile</goal> <!-- use this goal to weave all your test classes --> </goals> </execution> </executions> </plugin> </plugins> </build>
-
Now compile and run the application with
mvn run clean exec:java
-
This produced the following output
Checking security for: getName Mr. X
Troubleshooting
-
“[ERROR] Syntax error, annotations are only available if source level is 5.0″ – the AspectJ Maven Plugin needs to know the source level – the default place it’s looking for this information is project.build.java.target – like this entry in your pom.xml
<properties> <project.build.java.target>1.6</project.build.java.target> </properties>