Blogs

SpringSource Blog

Spring 3.1 M2: Configuration Enhancements

Chris Beams

As Juergen mentioned in his post yesterday, and as I've mentioned in my previous posts on 3.1 M1, one of the major themes of Spring 3.1 is completing our vision for code-based configuration in Spring. We think a modern enterprise Java application should have a choice between Java and XML as first class options for its configuration. In this post we'll see how Spring 3.1 M2 helps make this a reality.

Note that although Java-based configuration has been available since Spring 3.0, with this release it is now on par with many more of the XML-based features that have been developed over the years. We think the result is very appealing, and in some cases even offering clear advantages over XML-based configuration. In short: if you didn't consider it in 3.0 you really should look at it closely this time around.

Code equivalents for Spring's XML namespaces

If you've been watching things closely, you'll recall that we introduced the idea of FeatureSpecification classes and @Feature methods in 3.1 M1. As it turns out, we've decided to replace this with a different mechanism in 3.1 M2. Why? Because although FeatureSpecification classes provided a convenient mechanism for configuring features of the Spring container like annotation-driven transaction management and component-scanning, that convenience came with two downsides: lack of extensibility, and lack of implementation transparency. The more we thought about it, the more we realized we could do even better. While FeatureSpecification classes mirrored the XML namespaces closely through fluent APIs, the new solution takes a different shape – one specifically designed to take advantage of Java on its own terms.

For short, we call the new mechanism "@Enable" annotations. These annotations are applied at the type level on @Configuration classes. Let's take @EnableTransactionManagement for an example. Most users will be familiar with the following Spring XML snippet:

<beans>
  <tx:annotation-driven/>
</beans>

This of course enables Spring's support for transaction management using the @Transactional annotation. Now let's see the equivalent configuration in code:

@Configuration
@EnableTransactionManagement
public class AppConfig {
     // ...
}

Pretty simple, huh? Of course there's much more to say, and I would encourage everyone to take a look at the Javadoc for the @Enable annotations we've delivered in this release. You'll find they contain plenty of context, examples and references to important related types. It should be everything you need to get started. Of course, we'll also be updating the reference documentation prior to 3.1 GA, but we skipped this for M2 simply because the Javadoc has seen a lot of love.

Take a look as well at the Javadoc for @Configuration, which has been revised considerably in M2 to show off the major integrations with other annotations and mechanisms like the new Environment abstraction.

Regarding the @EnableWebMvc annotation, this is one great example where Java-based configuration proves to have real benefits over the XML namespace alternative. Rossen will be posting on this topic in detail later in this series, so stay tuned for that.


Hibernate SessionFactory builder APIs

Spring's support for Hibernate has always been one of the more popular features of the framework, and it's always been configured via XML. In M2 we've introduced the SessionFactoryBuilder and AnnotationSessionFactoryBuilder APIs which make code-based configuration of the Hibernate SessionFactory a snap. Check it out:

@Configuration
public class DataConfig {
     @Bean
     public SessionFactory sessionFactory() {
         return new AnnotationSessionFactoryBuilder()
             .setDataSource(dataSource())
             .setPackagesToScan("com.myco")
             .buildSessionFactory();
     }
}

See the Javadoc for more examples and specific details:


XML-free JPA configuration

Spring users working with JPA will be familiar with our LocalContainerEntityManagerFactoryBean. We've added a 'packagesToScan' property that allows you to drop persistence.xml altogether! This is, by the way, very similar to the property of the same name on Spring's Hibernate AnnotationSessionFactoryBean. Here's an example:

@Configuration
public class DataConfig {
     @Bean
     public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
         LocalContainerEntityManagerFactoryBean emf =
             new LocalContainerEntityManagerFactoryBean();
         emf.setDataSource(dataSource())
         emf.setPackagesToScan("com.myco")
         return emf;
     }
}


Leaving web.xml behind

Servlet 3.0 introduces some very interesting new facilities for code-based configuration of the servlet container. Essentially, the ServletContext API has been enhanced to allow users to register servlets, filters and listeners in a class-based or instance-based fashion. Take a look:

This means that it's now possible to register servlet-oriented components like Spring's DispatcherServlet and ContextLoaderListener programmatically, instead of declaratively via web.xml.

All that's missing is a bootstrap mechanism — a place to perform these registrations at a well-defined point in the servlet container lifecycle. Fortunately, Servlet 3.0 addresses this as well, with ServletContainerInitializer.

ServletContainerInitializer is a low-level SPI primarily targeted for use by frameworks like Spring. I'll leave the details to the Javadoc (links below), but in short, Spring 3.1 M2 now provides a very convenient WebApplicationInitializer interface that works in concert with the ServletContainerInitializer SPI to allow you to bootstrap the servlet container programmatically. Here's a quick example:

public class MyWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
      XmlWebApplicationContext appContext = new XmlWebApplicationContext()
      appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

      ServletRegistration.Dynamic dispatcher =
        container.addServlet("dispatcher", new DispatcherServlet(appContext));
      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
    }

}

As you can see, DispatcherServlet now sports a constructor that accepts a WebApplicationContext. Here's the Javadoc:

And while we used an XmlWebApplicationContext above, you can of course opt for AnnotationConfigWebApplicationContext instead and bootstrap completely via @Configuration classes.

When the spring-web module JAR is present on your classpath, your WebApplicationInitializer implementation(s) are detected and processed automatically by Spring in conjunction with the ServletContainerInitializer mechanism. This means you can package them exactly as you see fit in your application (goodbye, WEB-INF!) We've tested all of this successfully on Glassfish 3.1 and Tomcat 7.0.15, so now is a great time to get your feet wet with both Spring 3.1 and Servlet 3.0.

For complete usage instructions, take a look at the Javadoc for WebApplicationInitializer itself:

And for a complete (and concise) example of migrating from web.xml WebApplicationInitializer, check out this commit from the 'servlet3' branch of Spring's Greenhouse reference application:


Improved support for externalized values

M1 introduced the Environment abstraction and a unified PropertySource API. In M2, our goal is to make these components as easy to configure and use as possible. The new @PropertySource annotation allows you to contribute property sources to the environment from within your @Configuration classes:

 @Configuration
 @PropertySource("classpath:/com/myco/app.properties")
 public class AppConfig {
     @Autowired
     Environment env;

     @Bean
     public TestBean testBean() {
         TestBean testBean = new TestBean();
         testBean.setName(env.getProperty("testbean.name"));
         return testBean;
     }
 }

This is a different approach from the traditional PropertyPlaceholderConfigurer (<context:property-placeholder>) approach. Here, we're contributing a property source to the environment, injecting the environment into our @Configuration class, and then looking up the properties needed using the environment's #getProperty family of methods. Check out the Javadoc for @PropertySource and Environment for full details.


Summary

As you can see, we really do have a major theme going on here. From Java-based alternatives to Spring's XML namespaces and FactoryBeans to eliminating even non-Spring XML like web.xml and persistence.xml, we can now proudly say that Spring's code-based configuration is first-class throughout the framework. The only thing remaining is your feedback!

As Juergen mentioned, now is the time to try out 3.1 if you haven't already started. We're moving into the release candidate phase now, which is the perfect time to make improvements based on your real-world usage. Please let us know how it goes!

Oh, and one more thing… If you haven't already noticed, Spring is now on Twitter! Follow @springframework to stay up to date with releases and for insights into Spring from the framework itself. Hope to see you there and thanks for reading!

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • Twitter
 

47 responses


  1. I'm really excited with this new version and it's features.

     The development process of my company is going to speed up a lot with all of this.

    However, two issues come to my mind inmediatly:
    - In which version of IBM WebSphere could be deployed this programming model? WAS is the app server chosen by my company and sadly WAS 6.1 is the current version that we're using.

    - How long will it take to the rest of the Spring modules (Security, Roo and so on) to being adapted to this new release?

    In any case, good job and thanks for the effort.


  2. I want to use Java Configuration in my existing setup, but Spring IDE doesn't seem to know how to parse configuration beans properly. I had to switch back to XML configuration because I couldn't take all the erroneous warnings!


  3. How would one migrate

    to the @PropertySource annotation?

    I tried @PropertySource({"classpath:/META-INF/config.properties", "classpath:/META-INF/config-${com.google.appengine.runtime.environment}.properties"})

    but this doesn't work. FileNotFoundException for /META-INF/config-${com.google.appengine.runtime.environment}.properties

    {com.google.appengine.runtime.environment} is a System Property. It works with the XML property placeolder. S


  4. I just see my previous post didn't worked (xml was removed).

    I created this forum topic on the Spring forum: http://forum.springsource.org/showthread.php?110538-Spring-3.1.0.M2-PropertySource-flexibility&p=366504#post366504


  5. Javier, we do actually support WebSphere 6.1 still – and will keep up that support level for the entire Spring Framework 3.x branch. Our basic requirements are just Java SE 5 and Servlet 2.4 .

    You can deploy almost all of this model on WebSphere 6.1. Just Servlet 3.0 won't be available (that would require WebSphere 8), so you'll have to stick with web.xml for the time being – a minor limitation only.

    Juergen


  6. Great work guys! Any hint on where Tomcat 7.0.15 can be downloaded for those who want to try out the new Servlet 3.0 features? http://tomcat.apache.org/download-70.cgi only has 7.0.14 at the moment, which I think has a bug that prevents these features from working properly.


  7. Does packagesToScan support finding and scanning the ORM.xml (or mapping files) in the package. This will make easier to write the JPA queries


  8. Thanks for the information, Juergen.


  9. Cool, I'm looking forward to get rid of XML configuration completely! But what about the jee: namespace? Is there also an @EnableJavaEE annotation?


  10. @Joris – grab 7.0.15 here: http://people.apache.org/~markt/dev/tomcat-7/v7.0.15/


  11. @Donny – thanks for submitting https://jira.springsource.org/browse/SPR-8440. We'll check it out.


  12. @Marcel – as commented at https://jira.springsource.org/browse/SPR-8442:

    @PropertySource resource locations now support resolution of ${…} placeholders.

    See updated Javadoc at https://build.springsource.org/browse/SPR-TRUNKQUICK-JOB1-3772/artifact/javadoc-api/org/springframework/context/annotation/PropertySource.html


  13. @Harald – There will probably not be a dedicated equivalent for the jee: namespace. A JNDI lookup, for example, can be done programmatically without downsides within a @Bean method. You can do this with the native InitialContext API, or with Spring's JndiTemplate, if you choose.


  14. @Jon – regarding spurious warnings in STS when using @Configuration classes, please feel free to create an issue at https://issuetracker.springsource.com/browse/STS.


  15. I really like the @PropertySource annotation. It would be even more convenient if you don't have to inject the environment but could use @Value for getting the properties from the environment. Is that possible? Or planned?


  16. @Tobias,

    Either approach will work. See the "Working with externalized values" section of the Javadoc for @Configuration:

    http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/context/annotation/Configuration.html

    However, you may find that using context:property-placeholder and @Value is more cumbersome than necessary. When working directly against an injected Environment, there's no need to register the property-placeholder at all. And it tends to be the case that if you need one @Value injected, you need many (think about standard JDBC datasource properties, for example. Why not simply inject the Environment once and then perform lookups against it? Should be more concise and clear in the end. However, the choice is yours!


  17. Is it possible to set the JPA 2 specific SharedCacheMode using the XML-free JPA configuration?


  18. Yes, you can set the "javax.persistence.sharedCache.mode" property on LocalContainerEntityManagerFactoryBean (through its "jpaProperties"/"jpaPropertyMap").

    Juergen


  19. @Chris Beams,

    I do agree that setting a property-placeholder is cumbersome and overkill. Performing getProperty on the environment is OK but I guess being able to inject the properties directly through the @Values (or another) annotation will be even better.


  20. @Chris and Gabuzo
    That was my question: using @PropertySource and @Value without having to register a PropertySourcesPlaceholderConfigurer would be more convenient than injecting the environment and calling getProperty on it.
    Using @PropertySource could maybe register a PropertySourcesPlaceholderConfigurer automatically.


  21. @Tobias, @Gabuzo,

    Just a point of clarification on the comments above. Are you referring to using @Value in @Configuration classes or within individual @Component classes?

    In the case of @Configuration, I'd like to hear more why you find @Value injection to be better. In practice, we've found that this usually results in more verbosity, assuming that each @Value is individually injected into a field, and those fields then being referenced from within one or more @Bean methods. By contrast, @Inject'ing the Environment requires only one field, and then the #getProperty lookups are quite flexible and natural from that point forward.

    Please fill me in on why you would continue to prefer @Value injection into @Configuration classes, if that's actually the case.

    As for @Component classes, @Value injection is a good measure more appropriate there. Very often a @Component may need only one or two @Values injected, and the user may not want to depend so directly on a Spring interface like Environment in that context.

    Regarding automatic registration of a PropertySourcesPlaceholderConfigurer when using @PropertySource, I'm not sure this is the best approach given that it's not always what's desired, e.g. when going the Environment injection route. It's certainly easy enough to simply declare a @Bean method that returns a PSPC, and we could consider adding an @Enable annotation that does the same. Feel free to add an issue to this effect in JIRA if you like.


  22. @Chris

    I was talking about @Configuration classes, but I got your point. The more I think about it, the more I like your approach. It's even a little less annotation magic.
    And about an enable annotation for the propertyplaceholder: don't think that's necessary, because it's just a three liner @Bean method it would be replacing. On the other hand that's what the propertyplaceholder tag does: replacing three lines with one.


  23. Hey guys -

    These are some of the enhancements I'm most looking forward to with Spring 3.1. I've been using 3.1M2 to try to get the persistence.xml-less JPA instantiation running (using OpenJPA 2.1). Do you all know of an example yet with an XML Spring config that wires all the magic together correctly? I'm getting complaints about not having a persistence unit specified (which normally is in the persistence.xml file) and I'm not quite sure where or how to declare it.

    Thanks again,
    Matt


  24. And once you post something, you're sure to find the answer:


  25. I am looking for a good example of getting Servlet 3.0 (sans web.xml), Spring 3.1 and Spring Security to all work together well. Old school is easy, but this isn't.

    public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext applicationContext
    = new AnnotationConfigWebApplicationContext();
    applicationContext.scan("com.companyx.projectx");
    applicationContext.refresh();

    servletContext.addListener(new ContextLoaderListener(applicationContext));

    DelegatingFilterProxy delegatingFilterProxy
    = new DelegatingFilterProxy("springSecurityFilterChain", applicationContext);
    servletContext.addFilter("???", delegatingFilterProxy);

    Any help or direction to a helpful post would be very much appreciated. Thanks!


  26. @Tobias: Great, thanks for the follow-up.

    @Matt: Glad to hear you got what you need. Your link didn't come through. For posterity's sake, what was the example that ended up helping you?

    @HHD: In your example above, the "???" argument to #addFilter should simply be "springSecurityFilterChain". This is the equivalent of the filter-name element from web.xml. Does that get get you what you need?

    Also, if you don't actually need to #refresh() the context, it's better to let the ContextLoaderListener do this work for you. Both approaches are supported, but in your case, you can simply remove the call altogether.


  27. @Chris Thanks. That did help. It all ended up, be it right or wrong, like this:

    public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext applicationContext
    = new AnnotationConfigWebApplicationContext();

    applicationContext.scan("com.projectx");

    servletContext.addListener(new ContextLoaderListener(applicationContext));

    DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy("springSecurityFilterChain", applicationContext);
    FilterRegistration fr = servletContext.addFilter("springSecurityFilterChain", delegatingFilterProxy);
    fr.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), true, "/**");

    ServletRegistration.Dynamic dispatcherServlet
    = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(applicationContext));
    dispatcherServlet.setLoadOnStartup(1);
    dispatcherServlet.addMapping("/app/*");
    }

    That at least registers the security filter programmatically, judging from the logs at startup. However, for
    some reason … and it was working fine when using the web.xml approach versus with WebAppInitializer (which
    implements WebApplicationInitializer) … it is not seeing my UserDetailsServiceImpl and thus never seems to
    succeed. Is that a known issue, happening only when using the programmatic approach to bootstrapping?

    Oh well. Pilot error? Often, yes. This time – I don't think so!

    I also hate having this: dispatcherServlet.addMapping("/app/*");

    I really don't like having to have "app" in there, but it doesn't seem to work any other way. http://localhost:8080/projectx/index -vs- http://localhost:8080/projectx/app/index

    Thanks for all.

    Henry Dall


  28. @Henry,

    A couple things jump out, though they may not be the solution to your problem. First, it's probably not a good idea to try supplying the same applicationContext instance to both the ContextLoaderListener and the DispatcherServlet. These are really designed to be separate context instances that are then linked together by the dispatcher servlet in a hierarchical fashion. Consider using the no-arg constructor for DispatcherServlet or creating a distinct child context.

    Second, there shouldn't be any problem mapping "/*" instead of "/app/*", so long as you're on Tomcat 7.0.15 . What is your target platform here?

    Finally, this is probably isn't the best venue to continue such a detailed discussion. Consider submitting a pull request against the spring-framework-issues project (see the README at http://bit.ly/jTHHZ6), and we can look into this further via working code. Thanks!


  29. We currently use Spring 3 with Spring DM in an OSGi environment, and we do most of our configuration using @Configuration config classes. We'd like to use this java-config style for everything, but so far we haven't been able to figure out how to avoid having an XML file to declare osgi:reference and osgi:service beans.

    Is there anything in the new release that would enable us to declare our OSGi services and service references in our @Configuration code instead?


  30. Hi Chris,

    What would be the best way to configer StringTrimmerEditor globally using Spring 3.1 with Java Config?


  31. :)


  32. A little late but I just figured out that it's possible to use @Value togehter with @PropertySource. Here an example

    @Value("#{environment.driverClassName}")
    private String driverClassName;


  33. Excellent presentation at SpringOne yesterday on the new configuration. Your willingness to descend the discussion below the API that developers are accustomed to working with was very appreciated. It was insightful to hear why the Spring development team made certain decisions and gave me a better understanding of the framework. Content was extremely clear and focused, great job! Looking forward to the final release of 3.1 and your Getting Involved Session today.


  34. Thanks, @Kevin!


  35. I was trying to use AnnotationSessionFactoryBuilder with the latest spring 3.1.RC1 but couldn't find it anymore.

    Are these Builders deprecated now? What could be the best alternative of a Hibernate Session Factory with @Configuration classes?

    Thanks!


  36. @psilos,

    Indeed, we backed these out in RC1. This commit explains why, and makes note of the "LocalSessionFactoryBuilder" replacement in the orm.hibernate4 package.

    https://github.com/cbeams/spring-framework/commit/011e123e3fbc0a42600f60dec01f9d2ba02478ae


  37. Chris,

    The link above gets a 404. There seems to be a number of spring classes that are in the Greenhouse sample project that are no longer available in 3.1.0.RELEASE. Examples:
    org.springframework.jdbc.versioned.DatabaseChangeSet; org.springframework.jdbc.versioned.SqlDatabaseChange org.springframework.social.facebook.web.FacebookHandlerMethodArgumentResolver org.springframework.social.mobile.device.DeviceHandlerMethodArgumentResolver;

    Is there a place that has a map or explanation of where they went to or what replaced them?

    Thx


  38. Hello,

    Ok, I see that how can we configure jpa and hibernate without xml.
    But in case of jpa config where will the hibernate come into the picture ?
    As I know, we cant use jpa without Hibernate so where is connection between them ?

    Thanks in advance.

    CsCsaba


  39. Hi CsCsaba.

    The connection is made by setting the persistence provider to Hibernate on the LocalContainerEntityManagerFactoryBean. Like this:

    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactory.setPersistenceProvider(new HibernatePersistence());

    Regards,
    Paul


  40. Thanks Paul!


  41. If you want to put this together with Java configuration files -
    Read the javadocs for @Configuration

    In a nutshell you would put the following inside a spring config file :

    @Autowired Environment env;

    (note that the Javadoc says you can use @Inject but that's not working)

    then you can

    @Bean
    public Foo getMyFoo(){
    String user = env.getProperty("USER_NAME");
    return new Foo(user);
    }


  42. Hey!

    How about editing the blog posts (near the top) to indicate that these ideas are deprecated?!


  43. @mark, to which "deprecated ideas" are you referring? The content of this blog post is still accurate unless I've overlooked something. In any case, your comment reminded me that I should add such a note to the earlier 3.1 M1 blog post which announced FeatureSpecification support – a concept that was indeed replaced with @Enable annotations. I've added an update to the beginning of that article, but am still unsure what you're referring to in this one. Thanks.


  44. Chris….Oops, I was reading both articles and posted my earlier comment on the wrong one. I meant to post the "deprecated" comment on the earlier 3.1 M1 blog post. Thanks for the quick response


  45. Chris,

    Is there an alternative to write the datasource programmatically?

    Ex:


  46. Chris,

    Is there an alternative to write the datasource programmatically?

    Ex:


  47. The code didn't went on the comment

    jee:jndi-lookup id="dataSource" jndi-name="java:/couponpublisher-ds"

2 trackbacks

Leave a Reply