I must admit, when looking at Spring 3.0’s feature list for the first time I didn’t see one thing I wanted to use right away in my next project.
There was the Spring Expression Language,
the stereotype annotation model,
there was some Spring MVC stuff which I didn’t care about because I had nothing to do with Spring MVC back then,
and there was Java based configuration.
I saw potential in SpEL which indeed is very powerful. Now, almost three years later, I have used it here and then, but only very simple expressions, because anything a little more complicated always went into a Java component. Expressing complicated things through an expression never felt right. The stereotype annotation model is nice – but I never used it. It makes sense if you build up your own architecture relying on Spring’s component scanning / autowiring injection style – never happened in three years. And Spring MVC – I got to know it by now, and I really liked it, but you know, it’s a web framework, and you need a web framework when you need a web framework, you cannot use it always in every project using Spring.
When I look back now the biggest impact on my daily work with Spring definitely had the Java based configuration style, and I would never have thought that when looking at the feature list of Spring 3.0 back in 2009. Now I think that Java based configuration is one of those features that again proves the significance of the Spring Framework, and I’ll explain why.
The world before Spring 3.0
Before Spring 3.0 came out there were two dependency injection styles available in Spring Core, one based on XML and one based on annotations. The annotation style is very similar to the way JEE 5/6 handles DI, and the XML style felt somehow, I don’t know, outdated. At that time there were a lot of “why do we still need Spring” – discussions going on between Spring and JEE fans, and I read a lot of long discussions in comments under certain blog posts showing how serious people can get if you tell something bad about their toy.
Anyway, a little bit I felt like that as well. Do I still need Spring? Now, three years later, a definite “yes” is the answer, and of course it’s not just the Java based configuration that makes me feel like that, it’s the whole eco system that improved over the years, and you can still see the innovation (take Spring Data for example). But for me personally, a good part of that “yes” comes from Java based configuration.
But let’s get back to 2009.
Component scanning and autowiring
To be honest, I don’t like component scanning and autowiring that much, neither in Spring nor in JEE 5/6. Of course it always depends on the circumstances, the application, co-workers and so on, but in a bigger application it’s a little bit too much magic for my taste. And I believe there’s a violation of the dependency injection rule that a component should not know the bigger picture, in fact the whole configuration is spread among the business components.
Another disadvantage: there is not the one and only place where you can look for the configuration. And regarding Spring: there was still at least a little bit of XML necessary.
Okay, XML then?
We all know the disadvantages of XML by now, don’t we? Here are some of them:
- It’s not type-safe, you won’t get errors before starting the Spring ApplicationContext, and sometimes even later. Typing errors may slow you down.
- XML is verbose, so configuration files get big. It’s a good thing to split them up.
- Regarding splitting the configuration up: it’s not possible to navigate between different XML-files. If you wanna know where Spring bean xyService is defined, you’ll have to rely on full-text-search, like in the medieval age of programming.
- If you wanna build up libraries for usage (and you do that in big companies, where architecture teams provide libraries for other developers), it’s really hard to find XML configuration files in jars on the classpath, and it’s even harder to detect references in those files.
Some of those disadvantages may be covered up somehow when you’ve got the right tooling, but often you cannot choose your IDE. And not everything can be covered up.
So, both styles, annotation and XML based, have their advantages and disadvantages. They work well, of course, and will do in the future, I just wasn’t very enthusiastic about them anymore.
And then, with Spring 3.0, came Java based configuration, completed in Spring 3.1, and made me enthusiastic again.
Tooling
First of all, tooling support is perfect in any Java IDE. Out of the box you get
– type-safety check by compiling
– code completion
– refactoring support
– support for finding references in the workspace (even on jars in the classpath)
That’s one important part.
Language
The second part is about the language. I like Java, so why should I use different language construct for configurations? It feels really natural not to switch between Java and XML anymore. And of course, you can program anything you want directly in Java when creating Spring beans, like calling init-methods or static factory methods. No need for complicated ways to express that in XML.
Patterns
The third part is about patterns. Let’s take a look at some elegant patterns for Java based configuration.
Navigable configurations
Java is verbose, too, so it makes sense to split up big configurations into several configuration classes. You can separate bean definitions by component and/or by layer, for example one configuration for low level infrastructure like datasources, transaction manager and co, one for high level infrastructure components, one for repositories, one for services etc.
When connecting those configurations, you should use this pattern:
1@Configuration
2public class PartnerConfig {
3
4 @Bean
5 public PartnerService partnerService() {
6 return new PartnerServiceImpl();
7 }
8
9}
1@Configuration
2@Import(PartnerConfig.class)
3public class CashingConfig {
4
5 @Autowired
6 private PartnerConfig partnerConfig;
7
8 @Bean
9 public CashingService cashingService() {
10 return new CashingServiceImpl(partnerConfig.partnerService());
11 }
12
13}
We have two configuration files with the responsibility for different components. The CashingService depends on one of the components from PartnerConfig. By importing the PartnerConfig into the CashingConfig, all Spring beans from the PartnerConfig are available, but instead of autowiring those components directly, you wire the configuration class itself into the CashingConfig and use it to reference beans from it.
If you build up all your configuration files like this, it’s easy to navigate through all dependencies by jumping directly into the method that defines the used component, even if the configuration class is in a jar on the classpath.
Abstract dependency definitions
It’s easy to write a library and define through an abstract class or an interface needed components a user of the library has to add.
A simple example for this pattern is defining infrastructure components through an interface:
1public interface InfrastructureConfig {
2
3 public DataSource dataSource();
4
5 public PlatformTransactionManager transactionManager();
6
7}
As the author of that piece of software you create a configuration class like this:
1@Configuration
2public class ApplicationConfig {
3
4 @Autowired
5 private InfrastructureConfig infrastructureConfig;
6
7 @Bean
8 public JdbcTemplate jdbcTemplate() {
9 return new JdbcTemplate(infrastructureConfig.dataSource());
10 }
11
12 @Bean
13 public SomeService someService() {
14 return new SomeServiceImpl(jdbcTemplate());
15 }
16
17}
When somebody wants to use the library, he has to create an implementation of InfrastructureConfig and add it to the ApplicationContext. This way the developer of the library doesn’t need to think of environments in which the classes will run, it’s up to the user.
There is much potential in this pattern, you can think of abstract configuration classes defining some Spring beans fully, some just as abstract methods and providing default Spring beans for some types. Somebody using the library extends this configuration class, defines the abstract beans and overrides some of the default Spring beans. Whenever you’re developing some kind of framework, consider this pattern.
Multiple imports and profiles
Looking at the example code of the last paragraph, we can go a step further using Spring 3.1’s profiles:
1@Configuration
2@Import({ JndiInfrastructureConfig.class, StandaloneInfrastructureConfig.class })
3public class ApplicationConfig {
4
5 @Autowired
6 private InfrastructureConfig infrastructureConfig;
7
8 @Bean
9 public JdbcTemplate jdbcTemplate() {
10 return new JdbcTemplate(infrastructureConfig.dataSource());
11 }
12
13 @Bean
14 public SomeService someService() {
15 return new SomeServiceImpl(jdbcTemplate());
16 }
17
18}
This way we provide two implementations of the InfrastructureConfig interface. Since we can only autowire one of them into the ApplicationConfig, just one may be active. With the @Profile annotation, configuration classes just get imported if the profile mentioned in the annotation is active.
1@Profile("standalone")
2@Configuration
3public class StandaloneInfrastructureConfig implements InfrastructureConfig {
4
5 @Bean
6 public DataSource dataSource() {
7 BasicDataSource dataSource = new BasicDataSource();
8 dataSource.setUrl("someURL");
9 dataSource.setUsername("username");
10 dataSource.setPassword("password");
11 return dataSource;
12 }
13
14 @Bean
15 public PlatformTransactionManager transactionManager() {
16 return new DataSourceTransactionManager(dataSource());
17 }
18
19}
Somebody using the library now has the option to activate one of two default profiles or to implement another implementation of InfrastructureConfig and add it to the application context.
Conclusion
Since Spring 3.0 we have three different dependency injection styles, and my favorite is clear: Java based configuration has the best tooling support, feels natural and offers some nice patterns, especially when building frameworks and libraries. So give it a try!
And regarding the significance of the Spring Framework: right then when I felt that the existing dependency injection styles are not that perfect, Spring provided me with a third option, perfectly fitting my taste. I guess that’s innovation.
More articles
fromTobias Flohre
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Tobias Flohre
Senior Software Developer
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.