I thought it would be good to share some of the interesting features that Spring has added in its latest few installments. I have created a basic rest webapp project with a single demo object resource that uses a few “newer” Spring features. It uses Spring 3.2 MVC with Jackson 2 for marshaling, and SpringData for persistence. It runs on any web 3.0 container and mysql out of the box to keep it simple. In this post i’ll be talking about the feature known as JavaConfig and I’ll use this project for code examples.
JavaConfig (introduced in Spring 3.1) is Spring’s answer to the movement away from XML and towards a compilable DI specification. In short, everything you can currently do in traditional Spring XML configuration can now mostly be done in Java classes. For this example, i’ll be showing the JavaConfig way to define bean relationships from Java configuration files. JavaConfig also still supports using the Autowired methodology if you want to use that instead.
Setting it up couldn’t be easier. Create your new JavaConfig class annotated with @Configuration
and point to it in web.xml. Ignore the async-supported element. That is not needed for this example, but i’ll be writing up an entry about that as well.
You can consider WebConfig.java the parent spring configuration file that glues the application together. It extends WebMvcConfigurerAdapter to tell spring we are creating a MVC web application, it enables Spring MVC features, and it also imports other configurations for our app. Here is how its done.
- @EnableWebMvc is now used instead of “<mvc:annotation:driven/>” to support component scanning for spring mvc annotated classes.
- @Configuration tells spring that this is a JavaConfig file
- @Import tells spring to import other JavaConfig files (nicely providing a way to modularize your spring bean definitions)
- @ImportResource tells spring to import other resources, such as xml spring configuration. This is handy if you don’t want to fully commit to JavaConfig all at once or if a feature isn’t supported yet in JavaConfig.
Now lets look at the JavaConfig file for the controller portion of the application.
You can see that this is just another JavaConfig class, same as before, except this time we’ve declared some spring beans using @Bean annotated methods. This annotation replaces “<bean>” declarations from the xml style of configuration. The @Bean annotation allows scope to be declared, just like the xml element, and the code you write in the method is essentially a factory method for that bean. To get a reference to another bean, you simply just call the necessary factory method to create one and then use it however you’d like in the creation of another bean. The call to getAsyncHttpClient() from getSpringAsyncWebServiceProxyController() is an example of this. Spring will do the hard work of figuring out the scope of that bean and if it has been created previously or not before calling your factory method.
An interesting thing to note is that in the xml methodology you could just reference bean ids defined in other files and spring would just figure it out. Its nice to split spring application configs into multiple files for easier management. But now that the configs are compiled you obviously can’t just call random methods the same way you used to use bean ids defined elsewhere. There seem to be two ways to handle dependencies between config classes.
- Use @Autowired within your config class to inject another JavaConfig @Configuration class, and then call the @Bean method directly.
- Use @Autowired within your config class to inject a bean defined in another file.
There are arguments for using either. I prefer the 2nd case, and use it in the example code when I define springRestDemoService. This is just because I prefer leaning on some spring magic to decide the bean i want as opposed to coupling configuration classes. But either way would work just fine.
I hope you find this to be an interesting enough teaser to go and try using JavaConfig yourself. I have found the type safety of using a compiled DI descriptor to not only be more pleasant to use but also make the usage of Spring IOC much more efficient. No more edit xml, restart spring container, look at error, edit xml, repeat. Now my IDE just tells me there is an error immediately. awesome.