Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Configuration Enhancements in Spring 3.1

cbeams
October 26, 2011

Configuration Enhancements in Spring 3.1

As presented with Rossen Stoyanchev at SpringOne/2GX 2011 in Chicago, IL

cbeams

October 26, 2011
Tweet

More Decks by cbeams

Other Decks in Programming

Transcript

  1. YOU

  2. <beans> <bean id="foo" class="com.foo.Foo"/> <bean id="bar" class="com.foo.Bar"> <property name="foo" ref="foo"/>

    </bean> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> </beans>
  3. <beans> <bean id="foo" class="com.foo.Foo"/> <bean id="bar" class="com.foo.Bar"> <property name="foo" ref="foo"/>

    </bean> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> </beans>
  4. <beans> <bean id="foo" class="com.foo.Foo"/> <bean id="bar" class="com.foo.Bar"> <property name="foo" ref="foo"/>

    </bean> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <bean .../> <import resource="more-beans.xml"/> </beans>
  5. I mean, if you've got this package com.win; @Component public

    class TehAwesome { @Autowired public void setStuff(Stuff stuff) { ... } }
  6. I mean, if you've got this package com.win; @Component public

    class TehAwesome { @Autowired public void setStuff(Stuff stuff) { ... } } ... then this is kind of ironic, right? <context:component-scan base-package="com.win"/>
  7. bean definition @Configuration public class AppConfig { @Bean public QuoteService

    quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; } }
  8. bean definition // @Configuration classes =~ <beans/> documents @Configuration public

    class AppConfig { @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; } }
  9. bean definition @Configuration public class AppConfig { // @Bean methods

    ~= <bean/> elements @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; } }
  10. bean definition @Configuration public class AppConfig { @Bean public QuoteService

    quoteService() { RealTimeQuoteService quoteService = // instantiate return quoteService; } }
  11. bean definition @Configuration public class AppConfig { @Bean public QuoteService

    quoteService() { RealTimeQuoteService quoteService = ...; // configure return quoteService; } }
  12. bean definition @Configuration public class AppConfig { @Bean public QuoteService

    quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; // object managed by Spring } }
  13. bean definition @Import(OtherConfig.class) // =~ <import/> @Configuration public class AppConfig

    { @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; } }
  14. bean definition @Import(OtherConfig.class) @Configuration public class AppConfig { @Autowired QuoteSource

    quoteSource; // from OtherConfig @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; return quoteService; } }
  15. bean definition @Import(OtherConfig.class) @Configuration public class AppConfig { @Autowired QuoteSource

    quoteSource; @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; quoteService.setQuoteSource(quoteSource); // inject return quoteService; } }
  16. bootstrap and use public class Main { public static void

    main(String... args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); QuoteService quoteService = ctx.getBean(QuoteService.class); System.out.println(quoteService.currentValue("AAPL")); } }
  17. bootstrap and use public class Main { public static void

    main(String... args) { // bootstrap the Spring container ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); QuoteService quoteService = ctx.getBean(QuoteService.class); System.out.println(quoteService.currentValue("AAPL")); } }
  18. bootstrap and use public class Main { public static void

    main(String... args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); // retrieve the bean we want to use in type-safe fashion QuoteService quoteService = ctx.getBean(QuoteService.class); System.out.println(quoteService.currentValue("AAPL")); } }
  19. bootstrap and use public class Main { public static void

    main(String... args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); QuoteService quoteService = ctx.getBean(QuoteService.class); // use the bean however desired System.out.println(quoteService.currentValue("AAPL")); } }
  20. Java Configuration no equivalent to <namespace:*/> xml still required for

    tx mgmt, aop, etc no support in TestContext framework
  21. 3.1 @RunWith(SpringJUnit4ClassRunner.class) // ApplicationContext will be loaded from AppConfig @ContextConfiguration(classes=AppConfig.class)

    public class MyTest { @Autowired MyBean bean; @Test public void testXyz() { // assertions against bean } }
  22. Much more on testing at Sam's and Rossen's talk on

    Friday at 10:15 Updated TestContext reference documentation Testing with @Configuration classes blog post
  23. I mean, if you've got this package com.win; @Component public

    class TehAwesome { @Autowired public void setStuff(Stuff stuff) { ... } }
  24. I mean, if you've got this package com.win; @Component public

    class TehAwesome { @Autowired public void setStuff(Stuff stuff) { ... } } ... then this is kind of ironic ... <context:component-scan base-package="com.win"/>
  25. I mean, if you've got this package com.win; @Component public

    class TehAwesome { @Autowired public void setStuff(Stuff stuff) { ... } } ... but this makes a lot more sense. @ComponentScan("com.win")
  26. and if you've got this package com.win; @Repository public class

    WidgetRepo { @Transactional public void add(Widget widget) { ... } }
  27. and if you've got this package com.win; @Repository public class

    WidgetRepo { @Transactional public void add(Widget widget) { ... } } ... then why do this ... <tx:annotation-driven/>
  28. and if you've got this package com.win; @Repository public class

    WidgetRepo { @Transactional public void add(Widget widget) { ... } } ... when you could do this? @EnableTransactionManagement
  29. some component package com.startup; public class ChatterBox { public void

    saySomething() { System.out.println(randomWord()); } }
  30. some component package com.startup; public class ChatterBox { // (@Scheduled

    has been @Scheduled(fixedRate=1000) // around since Spring 3.0) public void saySomething() { System.out.println(randomWord()); } }
  31. some component package com.startup; public class ChatterBox { // "hey

    Spring, call this @Scheduled(fixedRate=1000) // method every second" public void saySomething() { System.out.println(randomWord()); } }
  32. configuration package com.startup.config; @Configuration @EnableScheduling // look for and process

    @Scheduled public class Config { @Bean public ChatterBox chatterBox() { return new ChatterBox(); } }
  33. configuration package com.startup.config; @Configuration @EnableScheduling public class Config { @Bean

    public ChatterBox chatterBox() { return new ChatterBox(); // saySomething() method } // called once per second }
  34. configuration package com.startup.config; @Configuration @EnableScheduling // ok, so what does

    this do? public class Config { @Bean public ChatterBox chatterBox() { return new ChatterBox(); } }
  35. SchedulingConfiguration.java package org.springframework.scheduling.annotation; @Configuration public class SchedulingConfiguration { // it's

    just registering the @Scheduled bean // post processor on your behalf public ScheduledAnnotationBeanPostProcessor sabpp() { return new ScheduledAnnotationBeanPostProcessor(); } }
  36. moving parts @Import now supported at annotation level @Enable* is

    just a naming convention @Configuration classes shipped out of the box
  37. (1) Default Configuration I.e. blank <name>-servlet.xml DispatcherServlet.properties HandlerMapping, HandlerAdapter ..

    and other types to instantiate by default Add own type .. turns off default types
  38. (2) MVC Namespace Minimize boilerplate for @MVC Targets the 80%

    use case More opinionated Serves as starting point
  39. MVC Namespace Experience Does a number of useful things Minimizes

    boilerplate Transparent .. ? Flexible .. ?
  40. Ease-of-use vs. Control A good starting point is important But

    transparency is key in MVC config So is flexibility
  41. (3) MVC Java Config (Spring 3.1) Designed with preivous experiences

    in mind Match MVC namespace capabilities More transparent More flexible
  42. MVC Java Config Example (Spring 3.1) // Equivalent to <mvc:annotation-driven/>

    @EnableWebMvc @Configuration public class WebConfig { }
  43. MVC Java Config Example (Spring 3.1) // Equivalent to <mvc:annotation-driven/>

    @EnableWebMvc // <-- What's behind ? @Configuration public class WebConfig { }
  44. <!-- 1. Change ApplicationContext type --> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.

    AnnotationConfigWebApplicationContext </param-value> </context-param> <!-- 2. Point to package with @Configuration classes --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> org.example.somepackage </param-value> </context-param>
  45. @EnableWebMvc @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override protected

    void addFormatters(FormatterRegistry registry) { // ... } @Override public void addInterceptors(InterceptorRegistry reg){ // Equivalent to <mvc:interceptors> } @Override public void addViewControllers(ViewControllerRegistry reg) { // Equivalent to <mvc:view-controller> } }
  46. Beyond The Common Case WebMvcConfigurer targets the 80% A good

    starting point Like the MVC namespace Transparency .. ? Flexibility .. ?
  47. Switch To Advanced Config Remove @EnableWebMvc Extend WebMvcConfigurationSupport Override the

    same methods as in WebMvcConfigurer Also override any @Bean methods!
  48. @Configuration public class WebConfig extends WebMvcConfigurationSupport { @Override public void

    addInterceptors(InterceptorRegistry reg){ // Equivalent to <mvc:interceptors> } @Override @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { // Create or let "super" create and customize // RequestMappingHandlerAdapter ... } }
  49. benefits easy to see what's going on easy to write

    your own scales smoothly from simple to sophisticated
  50. Java Configuration (3.1) completes the vision can configure all major

    container features mix and match styles as desired
  51. Hibernate 4 support Spring 3.1 RC1 builds against Hib 4.0.0.CR4

    3.1 GA will sync with 4.0 Final new orm.hibernate4 packaging
  52. Familiar? <bean id="sessionFactory" class="org.sfwk.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="mappingResources"> <list>

    <value>Person.hbm.xml</value> <value>Account.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> </property> </bean>
  53. Or even <bean id="sessionFactory" class="org.sfwk.orm.hib3.AnnotationSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="annotatedClasses">

    <list> <value>com.foo.Person</value> <value>com.foo.Account</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> </property> </bean>
  54. Or even <bean id="sessionFactory" class="org.sfwk.orm.hib3.AnnotationSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="annotatedClasses">

    <list> <value>com.foo.Person</value> <!-- again the irony --> <value>com.foo.Account</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> </property> </bean>
  55. standalone Hibernate exception translator @Bean public SessionFactory sessionFactory() { return

    new LocalSessionFactoryBuilder(dataSource()) .addAnnotatedClasses(Person.class, Account.class) .buildSessionFactory(); } @Bean public PersistenceExceptionTranslator exTranslator() { return new HibernateExceptionTranslator(); }
  56. JPA

  57. @Bean public LocalContainerEntityManagerFactoryBean emf() { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();

    emf.setDataSource(dataSource()); emf.setPersistenceXmlLocation( "classpath:META-INF/persistence.xml"); return emf; }
  58. @Bean public LocalContainerEntityManagerFactoryBean emf() { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();

    emf.setDataSource(dataSource()); emf.setPersistenceXmlLocation( "classpath:META-INF/persistence.xml"); // no more! return emf; }
  59. @Bean public LocalContainerEntityManagerFactoryBean emf() { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();

    emf.setDataSource(dataSource()); // scan classpath for JPA @Entity types emf.setPackagesToScan("com.win.entity"); return emf; }
  60. <web-app> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/dispatcher-config.xml

    </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <web-app>
  61. public class WebInit implements WebApplicationInitializer { @Override public void onStartup(ServletContext

    container) { XmlWebApplicationContext ctx = new XmlWebApplicationContext() ctx.setConfigLocation( "/WEB-INF/spring/dispatcher-config.xml"); ServletRegistration.Dynamic dispatcher = container.addServlet( "dispatcher", new DispatcherServlet(ctx)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
  62. public class WebInit implements WebApplicationInitializer { @Override public void onStartup(ServletContext

    container) { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext() ctx.register(DispatcherConfig.class); ServletRegistration.Dynamic dispatcher = container.addServlet( "dispatcher", new DispatcherServlet(ctx)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
  63. *which means that you really shouldn't worry, because XML support

    is definitely not going anywhere. This is a concern that commonly comes up when we talk about annotations and such, but we've said it before and we'll say it again: XML was, is, and ever will be a first class citizen in Spring. The changes in 3.1 just mean that if you don't want XML, you don't have to use it. That's all. kthx, bye.
  64. 3.1 RC1 is out Now is the time to test

    RC2 in a couple weeks GA by year end