Configuration Simplifications in Spring 3.0 |
|

Second in a series of posts on "Spring 3 Simplifications" started yesterday by Keith, I'd like to provide a very brief and hands-on introduction to Spring's new @Configuration annotation and related support.
As those that followed the Spring JavaConfig project will know, a @Configuration-annotated class serves much the same role as a Spring XML file. It provides a code-centric way of declaring Spring bean definitions using nothing more than methods and annotations. You might call it Plain Old Configuration*
This means that for simple situations, no XML will be required!
Let's get started. To demonstrate @Configuration functionality, I've created a very simple project in the new spring-samples SVN repository. You may want to sync up and build it right now. You'll need a Subversion client and recent version of Maven.
svn co https://src.springframework.org/svn/spring-samples/configuration-basic/trunk configuration-basic
cd configuration-basic
mvn clean test
[...]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
Eclipse .classpath and .project metadata is also included in the checkout, so you can import the project using the SpringSource Tool Suite, or any recent version of Eclipse with the m2eclipse plugin installed. In either case, use File->Import->Existing Projects into Workspace.
To begin, let's take a look at AppConfig.java. This @Configuration-annotated class serves the same role as an app-config.xml would in an XML-based Spring application. It's a good place to start when reviewing the project, because it serves as the 'blueprint' for how object instances are wired up and managed at runtime.
@Configuration
public class AppConfig {
public @Bean TransferService transferService() {
return new TransferServiceImpl(accountRepository());
}
public @Bean AccountRepository accountRepository() {
return new InMemoryAccountRepository();
}
}
Granted, this is trivial example of an application without even so much as a real JDBC DataSource in the mix. That's okay, the goal for this post is just to convey the basic concepts. The @Bean methods above will be recognized and invoked by the Spring container at the right time and the objects returned will be managed in the Spring container just like any other bean. You can see that dependencies between beans can be expressed simply as calls from one bean method to another. TransferServiceImpl needs an AccountRepository constructor argument, so simply call the accountRepository() method.
Savvy Spring users will look at this scenario, however, and ask the question "what about bean scoping"? It's a good question. As you probably know, all Spring beans have a scope. By default, a bean's scope is that of 'singleton', meaning that there will be one and only one instance of that bean per Spring container. Glancing at the code above, it seems that if we call accountRepository() multiple times, we'll actually create multiple instances, but this is not actually the case! When a @Configuration class is processed at runtime, it is dynamically subclassed (using CGLIB), and the subclass implementations of @Bean methods are enhanced to ensure that scoping semantics are respected.
As you can see, defining @Bean methods is pretty straightforward. Now, let's bootstrap the container and use those objects.
Take a look at the TransferServiceTest JUnit system test and its transfer100Dollars() @Test method. The first thing you'll notice is the use of AnnotationConfigApplicationContext. This new ApplicationContext implementation has been added in Spring 3 to support instantiation of the Spring container using @Configuration classes directly. The context is created with AppConfig.class as a constructor parameter, after which we retrieve the TransferService and AccountRepository beans by type with the getBean(Class
public class TransferServiceTest {
@Test
public void transfer100Dollars() {
// create the spring container using the AppConfig @Configuration class
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// retrieve the beans we'll use during testing
AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
TransferService transferService = ctx.getBean(TransferService.class);
// create accounts to test against
accountRepository.add(new Account("A123", 1000.00));
accountRepository.add(new Account("C456", 0.00));
// check account balances before transfer
assertThat(accountRepository.findById("A123").getBalance(), equalTo(1000.00));
assertThat(accountRepository.findById("C456").getBalance(), equalTo(0.00));
// perform transfer
transferService.transfer(100.00, "A123", "C456");
// check account balances after transfer
assertThat(accountRepository.findById("A123").getBalance(), equalTo(900.00));
assertThat(accountRepository.findById("C456").getBalance(), equalTo(100.00));
}
}
That's it! Simple, pure Java, type-safe configuration. We hope you'll find this a convenient and powerful addition to Spring's core dependency injection support.
Of course, we've just scratched the surface here today. So much more can be done with @Configuration classes and we'll explore those features in future posts. But don't wait for me – you can check them all out for yourself right now by reading the @Configuration section of the Spring 3 reference documentation. I encourage everyone to use this sample project as a starting point from which you can quickly road test the rest of this new support.
I look forward to your feedback. Enjoy playing with @Configuration and all the new Spring 3 features and have a happy holiday!
* Thanks to Erich Eichinger for (half-jokingly) coining the phrase 'Plain Old Configuration'. You can take a look at the work he and the Spring.NET team are doing with their similar 'CodeConfig' project here.
Similar Posts
- Spring 3.1 M1: Introducing @Profile
- Spring Framework 3.1 M1 released
- Spring 3.1 M1: Introducing FeatureSpecification support
- The new bean() pointcut
- Transactions, Caching and AOP: understanding proxy usage in Spring





Pablo says:
Added on December 22nd, 2009 at 8:40 pmHi,
Nice example. Will this go in the PetClinic?
I tried to do what is described in the doc as "@Configuration class-centric use of XML with @ImportResource".
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java-combining
But I didn't manage to get it working properly.
No warning about properties file not found and no placeholder resolved.
Could you try to add this in you sample project?
Thanks!
Pablo
Keesun Baik says:
Added on December 22nd, 2009 at 11:33 pmFirst of all, thank you for a simple and good explanation about @Configuration.
I just wonder why there ins't any Spring TextContext that supports @Configuration.
So I issued about this, but I didn't get any feedback until now.
http://jira.springframework.org/browse/SPR-6567
Dave T says:
Added on December 22nd, 2009 at 11:52 pmThis is not directly related to @Configuration, but to configuration in general. I can see where the EL would be helpful to get configuration for various properties of beans from a database or some other non-properties file source. Just create a bean that can retrieve those values, define it and then reference it from wherever needed in other bean definitions.
Sakuraba says:
Added on December 23rd, 2009 at 4:48 amNice.. but Guice looks cooler.
Bob Lee just has a talent for Java DSLs… I mean "bind(Foo.class).to(FooImpl.class).inSingleton();" just beats anything
Greg Turnquist says:
Added on December 26th, 2009 at 3:28 pmSpring Python also was inspired by Rod Johnson's blog entry that led to this: http://springpython.webfactional.com/1.1.x/reference/html/objects.html#objects-config-object
Baruch Sadogursky says:
Added on December 27th, 2009 at 9:44 amChris, can't wait to see all the amazing features you implemented in JavaConfig M4 available again!
Chris Love says:
Added on February 9th, 2010 at 12:45 amAnyway to use context:property-override with @Configuration class to load property values from a properties file?
Chris Beams (blog author) says:
Added on February 9th, 2010 at 1:07 pm@Chris – not at present. This has mostly to do with the fact that @Bean definitions have no 'property values' to override, per se. As opposed to the explicit model of providing 'property' elements in XML, in @Configuration classes, property methods are called by you, programmatically. You could achieve similar functionality to property override, but it would feel like a workaround by comparison.
Feel free to add a New Feature request to the [SPR project|http://jira.springframework.org/browse/SPR] with a clear use case and we'll be happy to consider other possibilities. Thanks!
Ignacio Coloma says:
Added on March 1st, 2010 at 4:25 pmYou should indicate the changes somehow in the JavaConfig reference Guide. IIRC it doesn't say "deprecated" anywhere.
I know that there are still some missing features, but for 90% of your needs @Configuration should be ok.
Chris Love says:
Added on March 8th, 2010 at 9:12 pmAny recommendation of documentation or examples on the 'EL' syntax for setting values. Such as
private @Value("#{jetProperties['jetBean.name']}") String name;
smallufo says:
Added on June 7th, 2010 at 1:52 amHi
What if there is another AccountRepository …
public @Bean AccountRepository accountRepository() {
return new DiskAccountRepository();
}
How should I specify which AccountRepository I need ?
I know I need something like @Qualifier , but I don't know how do I write the test code ?
Other examples in the net are all about XML settings… I need a pure-annotation example … thanks.
Chris Beams (blog author) says:
Added on June 7th, 2010 at 5:32 am@smallufo – if there's a second AccountRepository @Bean method within the same @Configuration class, it will by necessity have a different method name. Thus distinguishing between them when injecting into the TransferService is quite clear: either call accountRepository1(), or accountRepository2(). That said, when you're dealing with multiple @Configuration classes, or mixing and matching @Configuration and XML, ambiguities can arise. In these cases, @Qualifier works as you would expect it to, even on @Bean methods.
smallufo says:
Added on June 7th, 2010 at 6:24 amThank you , but I think you missed my point.
I mean , if there are two AccountRepository :
public @Bean AccountRepository accountRepository() {
return new InMemoryAccountRepository();
}
public @Bean AccountRepository accountRepository() {
return new DiskAccountRepository();
}
When testing :
AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
Spring will complain duplicated implementations…
How should I solve it ? Thanks a lot !
smallufo says:
Added on June 7th, 2010 at 6:26 amsorry , typo ,
I meant accountRepositoryMemory() and accountRepositoryDisk() , two difference methods.
Chris Beams (blog author) says:
Added on June 7th, 2010 at 7:03 amyou have a few choices:
getBeansOfType(AccountRepository.class) – fetch all implementations
getBean("accountRepositoryMemory", AccountRepository.class) – qualify by bean name
or, mark one of the @Bean methods with @Primary, and then simply call
getBean(AccountRepository.class) – the 'primary' bean will be the one returned
Eliot says:
Added on June 8th, 2010 at 3:43 pmIs there a way to download this project without SVN?
Because the SVN repository seems to have a problem now. Here is the error message I am getting…
>svn co https://src.sprin
gframework.org/svn/spring-samples/configuration-basic/trunk configuration-basic
svn: OPTIONS of 'https://src.springframework.org/svn/spring-samples/configuratio
n-basic/trunk': Could not resolve hostname `src.springframework.org': The reques
ted name is valid and was found in the database, but it does not have the correc
t associated data being resolved for.
(https://src.springframework.org)
Chris Beams (blog author) says:
Added on June 8th, 2010 at 5:31 pm@Eliot – Can you reach https://src.springframework.org/svn/spring-samples/configuration-basic/trunk/ with your browser?
Eliot says:
Added on June 8th, 2010 at 5:35 pm@Chris, I can reach URL via web browser fine. Perhaps the problem is that I work at a bank? They have very non standard network security here.
Chris Beams (blog author) says:
Added on June 8th, 2010 at 5:43 pmIt's possible there's something with your bank's network restricting this, but not terribly likely. If your browser can connect via https (port 443) to the given URL, it follows that any client should be able to do the same. when you say `svn co https://…` it's doing fundamentally the same thing as your browser. Perhaps try the same thing from home tonight, or somewhere outside your bank's network just to make sure it works there. Sorry you're having trouble. Just so we're clear, here's exactly what I just did to prove that it works for me:
cbeams@anakata:~>$ svn co https://src.springframework.org/svn/spring-samples/configuration-basic/trunk configuration-basic
A configuration-basic/.classpath
A configuration-basic/.project
A configuration-basic/src
A configuration-basic/src/test
A configuration-basic/src/test/java
A configuration-basic/src/test/java/org
A configuration-basic/src/test/java/org/springframework
A configuration-basic/src/test/java/org/springframework/samples
A configuration-basic/src/test/java/org/springframework/samples/config
A configuration-basic/src/test/java/org/springframework/samples/config/basic
A configuration-basic/src/test/java/org/springframework/samples/config/basic/account
A configuration-basic/src/test/java/org/springframework/samples/config/basic/account/TransferServiceTest.java
A configuration-basic/src/test/resources
A configuration-basic/src/test/resources/log4j.dtd
A configuration-basic/src/test/resources/log4j.xml
A configuration-basic/src/main
A configuration-basic/src/main/java
A configuration-basic/src/main/java/org
A configuration-basic/src/main/java/org/springframework
A configuration-basic/src/main/java/org/springframework/samples
A configuration-basic/src/main/java/org/springframework/samples/config
A configuration-basic/src/main/java/org/springframework/samples/config/basic
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/repository
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/repository/AccountRepository.java
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/repository/InMemoryAccountRepository.java
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/service
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/service/TransferService.java
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/service/TransferServiceImpl.java
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/AppConfig.java
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/domain
A configuration-basic/src/main/java/org/springframework/samples/config/basic/account/domain/Account.java
A configuration-basic/pom.xml
Checked out revision 479.
Mike says:
Added on September 24th, 2010 at 2:28 pmI am also able to connect to via browser however 2-3 svn client I have tried all of them giving same error
as Eliot
Could not resolve hostname `src.springframework.org': The reques
ted name is valid and was found in the database, but it does not have the correc
t associated data being resolved for.
Help would be appriciated.
zach t says:
Added on November 4th, 2010 at 2:48 pmcheck this out for the SVN client errors you guys are facing: http://nayidisha.com/techblog/accessing-remote-svn-repositories-from-eclipse
kaka2008 says:
Added on April 6th, 2011 at 1:15 amhi,what's @Configuration mean?
i find it works well without @Configuration
AlanB says:
Added on September 8th, 2011 at 5:47 amI am finding what looks like a bug with spring using @Configuration although it could be my lack of knowledge.
I am using the org.springframework.batch.test.JobLauncherTestUtils class (Spring batch test framework). I have 2 spring batch jobs defined in my xml context file.
If I define the job launcher in xml ie
then it works as expected using the job bean defined eventsBatchJob. Without defining the job property I would get an error saying that 2 beans of that type exist as it tries to autowire by type.
However if I try to use @Configuration instead of xml to define the "eventsJobLauncherTestUtils" bean I run into trouble.
@Bean(name = "eventsJobLauncherTestUtils")
public JobLauncherTestUtils eventsJobLauncherTestUtils() {
JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils();
//eventsBatchJob is injected
jobLauncherTestUtils.setJob(eventsBatchJob);
return jobLauncherTestUtils;
}
Despite having set the job property in code above and there is no error in that method it glitches with the error that it cannot autowire as 2 beans jobs of that type exist. This should not be the case as I have set the job property explicitly. It is my understanding the above code should work in the same way as the xml snippet I posted above. (using spring version 3.0.5 and tried 3.0.6 and the 3.1.2Milestone but to no avail).
The JobLauncherTestUtils class has an autowire annotation set for the setJob accessor but the class itself is not defined as spring bean via annotations.