Spring 3, Maven and Annotation Based Configuration
August 22nd, 2010 by Micha KopsThere 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..
Contents
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 applicationand 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>
Resources
- Seema Richard’s Blog: Annotation based configuration in Spring
- Theserverside.com – Introduction to the Spring Framework
- Keith Donalds: Obtaining Spring 3 Artifacts with Maven
- JavaPDA: Spring 3 Simplest App
- Roseindia.net: The @configuration annotation example in Spring 3.0 Framework
- Spring 3 Reference: Beans annotation config
- Spring 3 API JavaDocs
- Exec Maven Plugin Website
- Spring 3 Reference: JSR-250 implementation
- Google Guice Project Site
- JSR-330 Specification: Dependency Injection for Java
- JSR-250 Specification: Commons Annotations for Java
- Spring 3 Reference: Aspect oriented programming (AOP)
- Eclipse.org: The AspectJ Programming Guide
- AspectJ Maven Plugin
Tags: annotation, aop, aspectj, dependency injection, guice, IoC, JSR-250, JSR-330, maven, spring
September 7th, 2010 at 5:24 am
Thanks for the post!
Highly informative.
One comment though – I think that the schema location which specified in the file application-context.xml should have Spring 3 definitions if one will use Spring 3 (and not Spring 2.5 as mentioned).
Example: use spring-beans-2.5.xsd instead of spring-beans-3.0.xsd
September 7th, 2010 at 6:39 am
Thanks for the remark! I have updated the article :)
October 6th, 2011 at 7:22 am
Good kick start for Spring support for annotations.
January 21st, 2012 at 4:40 pm
In order to simplify main management, I have created https://jira.springsource.org/browse/SPR-9044. If you like the proposed approach, please vote for it.
September 19th, 2013 at 10:05 am
Great post! The ‘troubleshooting’ proved very handy for me, I was facing the same error when compiling aspectj aspects from Maven and that did the trick to resolve the error :)