
One of the central themes behind Spring 2.5 is comprehensive annotation-based configuration. We've been talking and blogging a lot about @Autowired, about Spring MVC's @RequestMapping and also about the new support for annotated tests written with JUnit4 or TestNG. @Autowired is certainly the central one of Spring 2.5's annotations, being available for use in service components, web components, unit tests - even domain objects when using Spring's @Configurable with AspectJ weaving. Spring MVC's @RequestMapping is equally flexible, supporting many variants of handler method signatures.
Today I'd like to take a different focus, namely on the wide-ranging set of dependency injection annotations supported by Spring. The following list includes the key annotations that can be used within Spring 2.5 beans:
This set of annotations encompasses all of Java EE 5's common annotations, which means that you may use the same common annotations in e.g. Servlet 2.5 servlets, JSF 1.2 managed beans and Spring managed beans. In other words, if you have some standard JSF 1.2 managed beans with annotation usage, you can take them as-is and move their definitions from faces-config to a Spring application context, without any change in the bean classes! This was an important design goal: Spring 2.5 may serve as straightforward replacement of the standard JSF 1.2 managed bean facility, simply through choosing SpringBeanFacesELResolver as your custom JSF ELResolver.
Configuration-wise, all you need to enable the complete set of annotations above is the following simple configuration element in your Spring application context:
Note that this setting is related to dependency injection only and does not require any parameterization. (For customization, consider defining Spring's individual AnnotationBeanPostProcessors instead, e.g. CommonAnnotationBeanPostProcessor). However, the annotation-config element does not activate any kind of proxying or special exporting. For such purposes, Spring provides more specific configuration elements:
This setting activates processing of transaction annotations, with the following two variants supported out of the box in Spring 2.5:
Side note: As with all of Spring's support options, the EJB 3.0 TransactionAttribute annotation will only be available if the EJB 3.0 API is actually present in the classpath. Spring automatically adapts to the presence of that API, analogous to the JSR-250 API or the JPA API (as referenced above).
The <tx:annotation-driven> element allows for transaction-specific configuration, e.g. the Spring PlatformTransactionManager to talk to (through the "transaction-manager" attribute) and the mode to operate in:
The explicit AspectJ mode of transaction annotation processing is new in Spring 2.5, allowing to use Spring's AnnotationTransactionAspect instead of traditional AOP proxies. This requires AspectJ compile-time weaving or load-time weaving, modifying the byte code of classes that happen to use the @Transactional annotation. Such weaving allows for supporting the annotation on any kind of method: be it public, protected or private - be it an external call or a call from within the object - the transaction will always kick in as specified by the annotation. This is in sharp contrast to traditional AOP proxies, where annotation-driven transactions are limited to public method calls coming in through the proxy.
If your environment is capable of load-time weaving, then the following configuration is sufficient for enabling AspectJ-style transaction annotation processing. Note that this requires either a runtime environment with built-in weaving support (e.g. WebLogic 10, OC4J 10.1.3.1, Tomcat configured with Spring's TomcatInstrumentableClassLoader) or Spring's VM agent to be specified on JVM startup ("-javaagent:spring-agent.jar").
<tx:annotation-driven mode="aspectj"/>
<bean id="transactionManager" class="…"/>
Finally, Spring 2.5 also provides a convenient configuration element for activating JMX exporting. The default MBeanServer will be autodetected on all common platforms, including the standard Java 5 platform MBeanServer as well as the special MBeanServers exposed by WebLogic 9/10 and WebSphere 6.
Spring-managed beans may then implement standard MBean/MXBean conventions, qualifying as MBean classes according to the JMX specification, or use the following annotations to declare their management signature (as known since Spring 1.2):
This indicates the real power of Spring's annotation configuration model: Different configuration concerns seamlessly merge into a unified whole, with consistent configuration style and unified component lifecycle - it's all still a standard Spring bean underneath, managed by a Spring ApplicationContext!
So much for this brief tour through Spring's core configuration annotations. If you are interested in hearing more about what's new in Spring 2.5 and how it all ties together, let me invite you to this Wednesday's Spring 2.5 webinar where I will be covering all key feature areas in Spring 2.5, ranging from Java 6 support to annotation-based configuration!

Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).
It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.
The sources: carplant.zip
During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.
public void doIt() {
}
public void log() {
System.out.println("Log!");
}
public static void main(String args[]) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});
Logger logger = (Logger)context.getBean("logger");
logger.doIt();
}
}
The file context2.xml is empty in this case, whereas context1.xml contains the following code:
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).
context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.
context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation2" method="log"/>
</aop:aspect>
</aop:config>
Running this will also show that the bean will be advised twice.
Note that I'm using a 2.1 milestone release here.

Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).
It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.
The sources: carplant.zip
During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.
public void doIt() {
}
public void log() {
System.out.println("Log!");
}
public static void main(String args[]) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});
Logger logger = (Logger)context.getBean("logger");
logger.doIt();
}
}
The file context2.xml is empty in this case, whereas context1.xml contains the following code:
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).
context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.
context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation2" method="log"/>
</aop:aspect>
</aop:config>
Running this will also show that the bean will be advised twice.
Note that I'm using a 2.1 milestone release here.

NOTE: This post has been updated as of May 31, 2007 to reflect the state of the 2.1-M2 official release
Two weeks ago I blogged about the new annotation-driven dependency injection capabilities of Spring 2.1, and I mentioned that I would follow-up with more info "later in the week". It turns out that was a bit optimistic, but the good news is the functionality has evolved quite a bit in the meantime. Therefore, to follow along with the examples here you will need to download the 2.1-M2 official release (or if you are one of the first people to read this updated entry and M2 is not yet available, you should grab at least nightly build #115 which you can download here).
The first thing I want to demonstrate is how to create an application context without using any XML. For those who have used Spring's BeanDefinitionReader implementations, this will look very familiar. Before creating the context however, we need a few "candidate" beans on the classpath. Continuing with the example from my previous blog, I have the following two interfaces:
…and these corresponding implementations:
@Autowired
private MessageRepository messageRepository;
public String greet(String name) {
Locale locale = Locale.getDefault();
if (messageRepository == null) {
return "Sorry, no messages";
}
String message = messageRepository.getMessage(locale.getDisplayLanguage());
return message + " " + name;
}
}
Map<String,String> messages = new HashMap<String,String>();
@PostConstruct
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
public String getMessage(String language) {
return messages.get(language);
}
}
Now as promised… to assemble this admittedly trivial "application" without any XML:
And the result:
Essentially, this is the exact same behavior as when using the component-scan XML element from the new "context" namespace (as demonstrated in my previous blog). However, I want to focus on some of the newer features as well as customization options. First, I will remove the @Repository annotation from the StubMessageRepository, and rerun the tests which produces the following exception:
Clearly the @Autowired annotation indicates a required dependency by default, but this can easily be switched by adding the 'required' parameter with a value of 'false', such as:
@Autowired(required=false)
private MessageRepository messageRepository;
…
The result after this modification:
To make things a bit more interesting, I will add the JDBC version of the MessageRepository (also from the previous post):
private SimpleJdbcTemplate jdbcTemplate;
@Autowired
public void createTemplate(DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@PostConstruct
public void setUpDatabase() {
jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
}
@PreDestroy
public void tearDownDatabase() {
jdbcTemplate.update("drop table messages");
}
public String getMessage(String language) {
return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
}
}
As long as the stub version still does not contain the @Repository annotation, rerunning the tests will now produce the following exception:
Obviously a chain reaction of autowiring failures has resulted since no DataSource is available in the context. However, as a firm believer in test-driven development, I would like to unit test my implementation prior to setting up the infrastructure. Luckily, the scanner is fairly customizable, and I can provide filters, such as:
boolean useDefaultFilters = false;
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, useDefaultFilters);
scanner.addExcludeFilter(new AssignableTypeFilter(JdbcMessageRepository.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));
scanner.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile("blog\\.Stub.*")));
scanner.scan("blog");
context.refresh();
GreetingService greetingService =
(GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);
As you can see, I disabled the 'defaultFilters' and explicitly added my own. In this case, that was not completely necessary since the default includes the @Component and @Repository annotations, but I wanted to show the various filtering options - including not only annotations, but also assignable types and even regular expressions. The main goal of course was to disable the JDBC version of MessageRepository in favor of the stub, and according to my result, that is exactly what happened:
Assuming that I am now ready to incorporate the JDBC version, I will likely need to include some XML configuration for the DataSource, such as:
Then, I can combine the scanning with an XmlBeanDefinitionReader (notice that I have reverted to the default filters only):
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog");
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/blog/dataSource.xml");
context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Hybrid Beans");
System.out.println(message);
The context contains both the scanned beans as well as those defined in XML, and the result is:
Up to this point, you've seen that 0 candidate beans will cause the autowiring to fail unless the 'required' parameter of @Autowired is set to false. Given that the autowiring is following 'by-type' semantics, more than 1 bean will cause a failure regardless of the required parameter's value. For example, after adding the @Repository annotation back to the StubMessageRepository and rerunning the previous example, I receive the following exception:
This can be resolved by switching to 'by-name' semantics - accomplished via Spring 2.1's support for the JSR-250 @Resource annotation:
@Resource(name="jdbcMessageRepository")
private MessageRepository messageRepository;
…
You probably noticed in the previous example that the bean name (as specified in the @Resource annotation) defaults to the decapitalized non-qualified classname. To override this behavior, it is possible to add your own implementation of the BeanNameGenerator strategy, such as:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
String fqn = definition.getBeanClassName();
return Introspector.decapitalize(fqn.replace("blog.", "").replace("Jdbc", ""));
}
}
Then providing this strategy to the scanner overrides the default:
And therefore, the name specified in the @Resource annotation can be modified accordingly:
NOTE: When relying on the container for autowiring, the default naming strategy is typically sufficient (i.e. it works "behind the scenes"). Therefore the naming strategy should only be considered for cases where you will be referring to beans by name elsewhere. Even then, for isolated cases it is much simpler to explicitly provide a bean name in the 'stereotype' annotation (e.g. @Repository("messageRepository")). Providing your own strategy can be useful if you are able to take advantage of naming conventions that are used consistently throughout your application (This particular example is a little contrived, but hopefully demonstrates that the strategy is very accommodating so that you can follow your own naming conventions).
So far all of the beans have been configured with the default 'singleton' scope, but scope resolution is another customizable strategy of the scanner. The default will look for a @Scope annotation on each component. For example, to configure the GreetingServiceImpl as a 'prototype', simply add the following:
While the default annotation approach is quite simple, scope is almost always a deployment-specific consideration. Therefore it often does not belong at the class-level or in the source code at all. For these reasons, the following strategy interface is available and may be specified on the scanner as with the BeanNameGenerator in the previous example:
Note that the name generation and scope resolution strategies may also be provided in the XML-based configuration, such as:
Likewise, custom filters can be added as sub-elements:
I realize this entry has already covered quite a bit of ground, but there is one last topic I would like to cover. In the previous post, I included an aspect with the <aop:aspectj-autoproxy/> element. Now I want to demonstrate how to add the autoproxy behavior with our standalone version. First, the aspect itself (same as last time):
private int invocationCount;
@Pointcut("execution(* blog.*Service+.*(..))")
public void serviceInvocation() {}
@Before("serviceInvocation()")
public void log() {
invocationCount++;
System.out.println("service invocation #" + invocationCount);
}
}
Next, I need to add an include filter for the @Aspect annotation (it is no longer included in the default filters):
And finally, I need to register the AspectJ annotation-based autoproxy creator (prior to calling refresh() on the context):
The result:
Hopefully this entry and the preceding one have provided a sufficient introduction to these new features of Spring 2.1. You should now have a decent understanding of how to combine the component scanning and annotation configuration in small doses alongside "traditional" Spring XML configuration if you prefer. Also, by providing your own filters, name generators, and scope resolvers, you can customize the configuration process. The official 2.1-M2 release contains more detailed information in the reference documentation.
Stay tuned to this Interface21 Team Blog to learn about more new features as we continue to progress from the current milestone phase toward the RC1 release of Spring 2.1, and if you are not particularly excited about the annotation-driven configuration, then you may want to keep an eye out for an upcoming blog by Costin Leau on Spring Java Configuration - which offers yet another alternative to XML but without the invasiveness of annotations in your application code.

Spring 2.0 introduced annotation support and annotation-aware configuration options that can be leveraged by Spring users who are developing with Java 5 (or later versions):
| for demarcating and configuring transaction definitions |
| for defining aspects along with @Pointcut definitions and advice (@Before, @After, @Around) |
| for indicating a class that is operating as a repository (a.k.a. Data Access Object or DAO) |
| for enforcing annotated bean properties are provided a value |
With Spring 2.1, this theme of annotation-driven configuration has been significantly extended and will continue to evolve as we progress toward the RC1 release. In fact, it is now possible to drive Spring's dependency injection via annotations. Furthermore, Spring can discover beans that need to be configured within an application context.
This blog entry will serve as a tutorial-style introduction to the basic features in 10 easy-to-follow steps. I will follow up later in the week with information on some more advanced features and customization options. If you are interested in alternative configuration options, you should also check out the Spring Java Configuration project and this blog.
This tutorial requires at least Java 5, and Java 6 is recommended (otherwise there is a single requirement at the end of step 1).
Grab spring-framework-2.1-m1-with-dependencies.zip. After extracting the archive, you will find the spring.jar and spring-mock.jar in the 'dist' directory. Add them to your CLASSPATH as well as the following (paths shown are relative to the 'lib' directory of the extracted 2.1-m1 archive):
(NOTE: If you are not running on Java 6, you will also need to add j2ee/common-annotations.jar)
Provide the interfaces and classes for the example. I have tried to keep it as simple as possible yet capable of demonstrating the main functionality. I am including all of the code and configuration in a single "blog" package. I would encourage following that same guideline so that the examples work as-is; otherwise, be sure to make the necessary modifications. First, the GreetingService interface:
Then, a simple implementation:
public void setMessageRepository(MessageRepository messageRepository) {
this.messageRepository = messageRepository;
}
public String greet(String name) {
Locale locale = Locale.getDefault();
String message = messageRepository.getMessage(locale.getDisplayLanguage());
return message + " " + name;
}
}
Since the service depends upon a MessageRepository, define that interface next:
And for now, a stub implementation:
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
public String getMessage(String language) {
return messages.get(language);
}
}
Define the beans for a Spring application context. Notice, that I am including a new 'context' namespace (NOTE: the 'aop' namespace is also included here and will be used in the final step):
<bean class="blog.StubMessageRepository"/>
</beans>
Obviously this configuration looks a little sparse. As you can probably guess, the 'context' namespace will soon play a role.
Provide a simple test case leveraging Spring's base support class:
public void setGreetingService(GreetingService greetingService) {
this.greetingService = greetingService;
}
@Override
protected String[] getConfigLocations() {
return new String[] { "/blog/applicationContext.xml" };
}
public void testEnglishWelcome() {
Locale.setDefault(Locale.ENGLISH);
String name = "Spring Community";
String greeting = greetingService.greet(name);
assertEquals("Welcome " + name, greeting);
}
public void testGermanWelcome() {
Locale.setDefault(Locale.GERMAN);
String name = "Spring Community";
String greeting = greetingService.greet(name);
assertEquals("Willkommen " + name, greeting);
}
}
Try running the tests and notice that they fail with a NullPointerException. This is to be expected since the GreetingServiceImpl has not been provided a MessageRepository. In the next two steps, you will add annotations to drive the dependency injection and initialization respectively.
Provide an @Autowired annotation on the GreetingServiceImpl's setter method, such as:
Then, add the 'annotation-config' element (from the new 'context' namespace) to your configuration:
<bean class="blog.GreetingServiceImpl"/>
<bean class="blog.StubMessageRepository"/>
</beans>
Rerun the tests. They will still fail, but if you look closely it's a new problem. The assertions fail, because the messages being returned are null. That means that the 'messageRepository' property has been set on the greeting service! Now, the StubMessageRepository simply needs to be initialized.
Spring provides a couple options for initialization callbacks: Spring's InitializingBean interface or an 'init-method' declaration within XML. As of Spring 2.1, JSR-250 annotations are supported - providing yet another option: @PostConstruct (and the @PreDestroy annotation can be used for destruction callbacks as you will see shortly). In the StubMessageRepository, add the annotation to the initialize method:
Rerun the tests. This time they should pass!
The @Autowired annotation can also be used for constructor-based injection. If you'd like to experiment with that option, remove the setter method from the GreetingServiceImpl and add this constructor instead (then rerun the tests):
If preferred, you can even use field-injection. Remove the constructor, add the annotation directly to the field, and rerun the tests. The code should look like this:
Add a JDBC-based repository implementation of the MessageRepository:
private SimpleJdbcTemplate jdbcTemplate;
@PostConstruct
public void setUpDatabase() {
jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
}
@PreDestroy
public void tearDownDatabase() {
jdbcTemplate.update("drop table messages");
}
public String getMessage(String language) {
return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
}
}
Notice that in addition to @PostConstruct for initialization, this is using @PreDestroy to mark a method to be called on destruction. One thing is unclear from this implementation: how will the SimpleJdbcTemplate be provided? One option would be to provide a bean definition for the template. Another option would be to somehow provide a DataSource implementation to the template's constructor. Add the following (annotated) method:
This demonstrates dependency injection working with an arbitrary method (not a traditional 'setter'). This will be tested in the course of the next step.
In Spring 2.1, "candidate" beans can even be discovered rather than provided explicitly in the XML as above. Certain annotations are recognized by default. This includes the @Repository annotation as well as a new @Component annotation. Add those two annotations to JdbcMessageRepository and GreetingServiceImpl respectively:
Then modify the XML file by removing the existing explicit bean definitions and simply adding a component-scan tag:
Then, add just the DataSource bean definition and the new tag for configuring property placeholders:
<context:property-placeholder location="classpath:blog/jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
… and the jdbc.properties file itself:
Rerun the tests, and you should see the green bar even though only the data source has been defined in XML.
Finally, add an aspect (the @Aspect annotations are also automatically detected by default):
private int invocationCount;
@Pointcut("execution(* blog.*Service+.*(..))")
public void serviceInvocation() {}
@Before("serviceInvocation()")
public void log() {
invocationCount++;
System.out.println("service invocation #" + invocationCount);
}
}
And to activate automatic proxy generation, simply add the following tag to the xml:
Rerun the tests, and you should see the log messages!
NOTE: the scanning and configuration process can be initiated without any XML and can be customized (e.g. detect your own annotations and/or types). I will discuss those features and more in the next post.
In the mean time, I hope this post will serve its purpose well - providing hands-on experience with these new Spring 2.1 features. As always, we are looking forward to feedback from the community, so please feel free to leave comments!

Last Friday I finished a training session at a client of ours. Because I had some time to kill in the hotel I was staying in, I polished the sample application I coded up during the training to post it online for the guys of the training. Usually I try to find a little sample application specific to the client's domain to use during the training. This makes it a bit more lively instead of some of the HelloWorld examples.
This client is a big car brand, that have adopted Spring widely throughout their organization. That's why I created a CarPlant system capable of producing cars. Below you can find a little UML diagram displaying the (rather tiny) domain model and services in the system.
In the application, I'm using various techniques that you might not have seen that much yet. Here's a small list of what you can expect:
The sample uses Maven, so you have to have that installed, because I haven't included the dependencies.

The source code for the sample: CarPlant.zip