Spring 3.1 Review (and 3.2 Preview)

Spring 3.1 Review (and 3.2 Preview)

As delivered at the Cloud Foundry Open Tour 2012 events in Kiev and Moscow.

21874091836ab7d3a769c1a89a0702f3?s=128

Chris Beams

April 24, 2012
Tweet

Transcript

  1. 3.
  2. 4.
  3. 5.

    YOU

  4. 9.

    major themes first-class environment support code-based configuration new cache abstraction

    @MVC improvements third-party library and specification support
  5. 14.

    PropertySource API abstraction for any source of key/value pairs .properties

    files system properties environment variables servlet context params JNDI
  6. 16.

    StandardEnvironment includes by default PropertySources for: JVM system properties (-D

    flags) system environment variables suitable for use in standalone (i.e. non-web) apps
  7. 17.

    StandardServletEnvironment includes by default PropertySources for: JVM system properties (-D

    flags) system environment variables servlet config and context params JNDI
  8. 18.

    Putting the Environment to use All Spring ApplicationContext types now

    contain an Environment You can create and register your own Environment And/or customize with your own PropertySources Using ConfigurableEnvironment API or with @PropertySource annotation
  9. 20.

    PropertySourcesPlaceholderConfigurer <beans ...> <context:property-placeholder location="classpath:com/company/db.properties"/> <bean id="dataSource" class="org.sfwk.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass"

    value="${db.driver}"/> <property name="url" value="${db.driver}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </bean> </beans>
  10. 21.

    PropertySourcesPlaceholderConfigurer <beans ...> <context:property-placeholder location="classpath:com/company/db.properties"/> <bean id="dataSource" class="org.sfwk.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass"

    value="${db.driver}"/> <property name="url" value="${db.driver}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </bean> <!-- in 3.1, ${...} placeholders may be --> <!-- from 'db.properties' as well as all --> <!-- property sources registered with the --> </beans> <!-- Environment -->
  11. 22.

    @Inject the Environment @Configuration public class DbConfig { @Bean public

    DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); return ds; } }
  12. 23.

    @Inject the Environment @Configuration public class DbConfig { @Bean public

    DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); // configure and return the data source ... return ds; } }
  13. 24.

    @Inject the Environment @Configuration public class DbConfig { @Bean public

    DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  14. 25.

    @Inject the Environment @Configuration public class DbConfig { @Bean public

    DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); // where do these properties ds.setUsername(...); // come from? ds.setPassword(...); return ds; } }
  15. 26.

    @Inject the Environment @Configuration public class DbConfig { @Bean public

    DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  16. 27.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Bean

    public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  17. 28.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  18. 29.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; // injected from the enclosing // ApplicationContext @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  19. 30.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(...); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  20. 31.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(env.getPropertyAsClass("db.driver")); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); return ds; } }
  21. 32.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(env.getPropertyAsClass("db.driver")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(...); ds.setPassword(...); return ds; } }
  22. 33.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(env.getPropertyAsClass("db.driver")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(env.getProperty("db.username")); ds.setPassword(...); return ds; } }
  23. 34.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(env.getPropertyAsClass("db.driver")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(env.getProperty("db.username")); ds.setPassword(env.getProperty("db.password")); return ds; } }
  24. 35.

    @Inject the Environment @PropertySource("classpath:/com/company/app/db.properties") @Configuration public class DbConfig { @Inject

    Environment env; @Bean public DataSource dataSource() { SimpleDriverDataSource ds = new SimpleDriverDataSource(); ds.setDriverClass(env.getPropertyAsClass("db.driver")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(env.getProperty("db.username")); ds.setPassword(env.getProperty("db.password")); return ds; // property values may be resolved from } // 'db.properties' or any other PropertySource } // registered with the Environment
  25. 38.

    abc-config.xml <beans> <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c"

    class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); // ... }
  26. 39.

    abc-config.xml <beans profile="dev"> <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean

    id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); // ... }
  27. 40.

    abc-config.xml <beans profile="dev"> <!-- only register if "dev" active -->

    <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); // ... }
  28. 41.

    abc-config.xml <beans profile="dev"> <!-- only register if "dev" active -->

    <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); // oops! "dev" profile not active, // so bean "a" is not found }
  29. 42.

    abc-config.xml <beans profile="dev"> <!-- only register if "dev" active -->

    <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); }
  30. 43.

    abc-config.xml <beans profile="dev"> <!-- only register if "dev" active -->

    <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); }
  31. 44.

    abc-config.xml <beans profile="dev"> <!-- only register if "dev" active -->

    <bean id="a" class="com.company.A"/> <bean id="b" class="com.company.B"/> <bean id="c" class="com.company.C"/> </beans> Main.java public static void main(String... args) { GenericXmlApplicationContext ctx = new GXAC(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.load("classpath:com/company/*-config.xml"); ctx.refresh(); ctx.getBean("a"); // "dev" profile is active, so // bean "a" is available }
  32. 45.

    profile use cases differing configurations across dev/test/prod lifecycle customer A

    vs. customer B deployments portability across traditional and cloud environments ...
  33. 46.

    dev-datasource-config.xml <beans profile="dev"> <bean id="dataSource" class="org.opensource.InMemoryDB"> <property name="driverClass" value="..."/> <property

    name="url" value="..."/> <property name="username" value="..."/> <property name="password" value="..."/> </bean> </beans>
  34. 47.

    dev-datasource-config.xml <beans profile="dev"> <bean id="dataSource" class="org.opensource.InMemoryDB"> <property name="driverClass" value="..."/> <property

    name="url" value="..."/> <property name="username" value="..."/> <property name="password" value="..."/> </bean> </beans> prod-datasource-config.xml <beans profile="prod"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myds"/> </beans>
  35. 50.

    datasource-config.xml <beans> <beans profile="dev"> <bean id="dataSource" class="org.opensource.InMemoryDB"> <property name="driverClass" value="..."/>

    <property name="url" value="..."/> <property name="username" value="..."/> <property name="password" value="..."/> </bean> </beans> <beans profile="prod"> </beans> </beans>
  36. 51.

    datasource-config.xml <beans> <beans profile="dev"> <bean id="dataSource" class="org.opensource.InMemoryDB"> <property name="driverClass" value="..."/>

    <property name="url" value="..."/> <property name="username" value="..."/> <property name="password" value="..."/> </bean> </beans> <beans profile="prod"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myds"/> </beans> </beans>
  37. 56.

    <web-app> <servlet> <servlet-name>main</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>spring.profiles.active</param-name> <param-value>p1,p2,p3</param-value> </init-param>

    <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> <!-- ... --> <web-app>
  38. 61.

    app-config.xml <beans> <bean id="foo" class="com.company.Foo"> <property name="bar" ref="bar"/> </bean> <bean

    id="bar" class="com.company.Bar"/> </beans> ... new GenericXmlApplicationContext("app-config.xml");
  39. 62.

    AppConfig.java @Configuration public class AppConfig { @Bean public Foo foo()

    { Foo foo = new Foo(); foo.setBar(bar()); return foo; } @Bean public Bar bar() { return new Bar(); } } ... new AnnotationConfigApplicationContext(AppConfig.class);
  40. 63.
  41. 65.

    XML namespaces <beans> <!-- scan for all @Component-annotated classes -->

    <context:component-scan base-package="com.company"/> </beans>
  42. 66.

    XML namespaces <beans> <!-- scan for all @Component-annotated classes -->

    <context:component-scan base-package="com.company"/> <!-- handle any @Transactional annotations --> <tx:annotation-driven/> </beans>
  43. 67.

    XML namespaces <beans> <!-- scan for all @Component-annotated classes -->

    <context:component-scan base-package="com.company"/> <!-- handle any @Transactional annotations --> <tx:annotation-driven/> <!-- handle any @Scheduled annotations --> <task:annotation-driven/> </beans>
  44. 68.

    XML namespaces <beans> <!-- scan for all @Component-annotated classes -->

    <context:component-scan base-package="com.company"/> <!-- handle any @Transactional annotations --> <tx:annotation-driven/> <!-- handle any @Scheduled annotations --> <task:annotation-driven/> <!-- ... --> </beans>
  45. 80.

    AbcConfig.xml @Configuration public class AbcConfig { @Bean A a() {

    return new A(); } @Bean B b() { return new B(); } @Bean C c() { return new C(); } }
  46. 81.

    AbcConfig.xml @Configuration @Profile("dev") public class AbcConfig { @Bean A a()

    { return new A(); } @Bean B b() { return new B(); } @Bean C c() { return new C(); } }
  47. 83.

    TestContext framework @ContextConfiguration and friends introduced in Spring 2.5 big

    help with integration tests until 3.1, worked only with XML
  48. 92.

    WebApplicationInitializer Spring 3.1 introduces WebApplicationInitializer API builds on Servlet 3.0

    ServletContainerInitializer auto-detected on servlet container startup eliminates need for web.xml entirely
  49. 93.

    <web-app> <servlet> <servlet-name>main</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>main</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <web-app>
  50. 94.

    WebApplicationInitializer equivalent public class MyWAI implements WebApplicationInitializer { @Override public

    void onStartup(ServletContext servletContext) { XmlWebApplicationContext appContext = new XmlWebApplicationContext() appContext.setConfigLocation( "/WEB-INF/spring/dispatcher-config.xml"); Dynamic servlet = servletContext.addServlet( "main", new DispatcherServlet(appContext)); servlet.addMapping("/"); servlet.setLoadOnStartup(1); } }
  51. 95.

    even better - 100% XML-free public class MyWAI implements WebApplicationInitializer

    { @Override public void onStartup(ServletContext servletContext) { AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext() appContext.register(AppConfig.class); Dynamic servlet = servletContext.addServlet( "main", new DispatcherServlet(ctx)); servlet.addMapping("/"); servlet.setLoadOnStartup(1); } }
  52. 98.

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

    emf.setDataSource(dataSource()); emf.setPersistenceXmlLocation( "classpath:META-INF/persistence.xml"); return emf; }
  53. 99.

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

    emf.setDataSource(dataSource()); emf.setPersistenceXmlLocation( "classpath:META-INF/persistence.xml"); // no more! return emf; }
  54. 101.

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

    emf.setDataSource(dataSource()); // scan classpath for JPA @Entity types emf.setPackagesToScan("com.biz.app"); return emf; }
  55. 104.

    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>
  56. 105.

    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>
  57. 109.
  58. 110.

    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(); }
  59. 113.

    "but what about XML?" don't worry... Spring XML will always

    remain first-class code config is there for those that want it
  60. 121.

    @EnableCaching annotation @Configuration @EnableCaching class AppConfig { @Bean public CacheManager

    cacheManager() { ConcurrentMapCacheManager mgr = new ConcurrentMapCacheManager(); mgr.setCacheNames(Collections.singleton("books")); return mgr; } }
  61. 122.

    out-of-the-box implementations for Ehcache Concurrent map (in-memory) any provider can

    be plugged in GemFire, Coherence, etc. JCache support in Spring 3.2
  62. 124.

    Improvements in @MVC new HandlerMethod-based approach flash attribute support @Validated

    annotation supporting JSR-303 groups @Valid support on @RequestBody method args HDIV security framework integration
  63. 125.

    Improvements in @MVC complete support for code config with @EnableWebMvc

    even more flexibility important improvements for RESTful services too much to cover here! see @rstoyanchev's spring-mvc-3.1-update
  64. 128.

    Hibernate 4.x support currently up to date with 4.1.0 now

    in dedicated orm.hibernate4 package includes LocalSessionFactoryBuilder discussed earlier
  65. 132.
  66. 134.

    a typical component package com.company; public class Baz { private

    final Foo foo; private Bar bar; public Baz(Foo foo) { this.foo = foo; } public setBar(Bar bar) { this.bar = bar; } }
  67. 135.

    and it's typical config <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...> <bean id="foo"

    class="com.company.Foo"> <bean id="bar" class="com.company.Bar"> <bean name="baz" class="com.company.Baz"> <constructor-arg ref="foo"/> <property name="bar" ref="bar"/> </bean> </beans>
  68. 136.

    ... with p: namespace <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" ...> <bean

    id="foo" class="com.company.Foo"> <bean id="bar" class="com.company.Bar"> <bean name="baz" class="com.company.Baz" p:bar-ref="bar"> <constructor-arg ref="foo"/> </bean> </beans>
  69. 137.

    ... with c: namespace <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" ...>

    <bean id="foo" class="com.company.Foo"> <bean id="bar" class="com.company.Bar"> <bean name="baz" class="com.company.Baz" p:bar-ref="bar" c:foo-ref="foo"/> </beans>
  70. 138.
  71. 142.
  72. 144.
  73. 145.
  74. 149.

    new build system from Ant/Ivy to Gradle used to take

    a whole blog post to explain now just one command
  75. 152.
  76. 159.
  77. 160.
  78. 164.
  79. 165.
  80. 167.

    Asynchronous request processing support in @MVC for Servlet 3.0/3.1 async

    may also incorporate Web Sockets stay tuned to blog.springsource.com feedback please!
  81. 170.

    Third-party libs and spec support JPA 2.1 (SPR-8194) JSF 2.2

    (SPR-8104) JMS 2.0 (SPR-8197) JCache 1.0 (SPR-8774) Bean Validation 1.1 (SPR-8199)
  82. 172.

    Ease of use migrate away from CGLIB (SPR-8190) logging improvements

    (SPR-8122) error-reporting improvements (SPR-8204)
  83. 173.

    Roadmap 3.1.1 is out, 3.1.2 on the way 3.2 M1

    just around the corner 3.2 GA around year-end 2012