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

Modern Enterprise Application Configuration with Spring

cbeams
November 08, 2012

Modern Enterprise Application Configuration with Spring

As delivered at Øredev 2012 in Malmo, Sweden.
- Original session listing: http://oredev.org/2012/sessions/modern-enterprise-application-configuration-with-spring
- Video: https://vimeo.com/54942353

cbeams

November 08, 2012
Tweet

More Decks by cbeams

Other Decks in Programming

Transcript

  1. you

  2. enterprise think big (big enough to hire own devs) typically

    not tech companies finance, media, insurance, gov't, ...
  3. enterprise app configuration what components are involved? how are they

    parameterized? what dependencies exist? how are they satisfied?
  4. spring == comprehensive infrastructural support ...and there's a lot of

    infrastructure out there! configuration is just one (important) concern
  5. the approach POJOs + 3rd party components ↓ configuration ┌─────────────────────┐

    instructions → │ the Spring container│ └─────────────────────┘ ·
  6. the approach POJOs + 3rd party components ↓ configuration ┌─────────────────────┐

    instructions → │ (ApplicationContext)│ └─────────────────────┘ ·
  7. the approach POJOs + 3rd party components ↓ configuration ┌─────────────────────┐

    instructions → │ the Spring container│ └─────────────────────┘ ·
  8. the approach POJOs + 3rd party components ↓ configuration ┌─────────────────────┐

    instructions → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  9. you get one consistent mechanism for config fail-fast behavior at

    startup dependency injection vs dependency lookup ... leading to simple, testable POJO components ability to enhance behavior through AOP
  10. config style POJOs + 3rd party components ↓ configuration ┌─────────────────────┐

    instructions → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  11. config style POJOs + 3rd party components ↓ <beans> ┌─────────────────────┐

    XML → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  12. config style POJOs + 3rd party components ↓ <beans> ┌─────────────────────┐

    XML → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  13. config style POJOs + 3rd party components ↓ <beans> +

    ┌─────────────────────┐ <namespace:*> → │ the Spring container│ XML └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  14. config style POJOs + 3rd party components ↓ @Component- ┌─────────────────────┐

    scanning → │ the Spring container│ + @Autowired └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  15. @Component-scanning + @Autowired eliminates a lot of xml really concise,

    convenient now widely used especially for MVC @Controllers
  16. @Component-scanning + @Autowired can't wire up third-party code ambiguities can

    arise (enter @Qualifier) still requires xml to bootstrap
  17. I mean, if you've got this package com.foo; @Component public

    class Bar { @Autowired public void setFoo(Foo foo) { ... } }
  18. I mean, if you've got this package com.foo; @Component public

    class Bar { @Autowired public void setFoo(Foo foo) { ... } } ... then this is kind of ironic, right? <context:component-scan base-package="com.foo"/>
  19. config style POJOs + 3rd party components ↓ @Component- ┌─────────────────────┐

    scanning → │ the Spring container│ + @Autowired └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  20. config style POJOs + 3rd party components ↓ @Configuration ┌─────────────────────┐

    + @Bean → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  21. bean definition @Configuration public class AppConfig { @Bean public QuoteService

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

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

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

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

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

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

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

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

    quoteSource; @Bean public QuoteService quoteService() { RealTimeQuoteService quoteService = ...; quoteService.setQuoteSource(quoteSource); // inject return quoteService; } }
  30. 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")); } }
  31. 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")); } }
  32. 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 typesafe fashion QuoteService quoteService = ctx.getBean(QuoteService.class); System.out.println(quoteService.currentValue("AAPL")); } }
  33. 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")); } }
  34. if you've got this package com.foo; @Component public class Bar

    { @Autowired public void setFoo(Foo foo) { ... } }
  35. if you've got this package com.foo; @Component public class Bar

    { @Autowired public void setFoo(Foo foo) { ... } } ... then this is kind of ironic ... <context:component-scan base-package="com.foo"/>
  36. I mean, if you've got this package com.foo; @Component public

    class Bar { @Autowired public void setFoo(Foo foo) { ... } } ... but this makes a lot more sense. @ComponentScan("com.foo")
  37. and if you've got this package com.foo; @Repository public class

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

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

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

    saySomething() { System.out.println(randomWord()); } }
  41. some component package com.foo; public class ChatterBox { @Scheduled(fixedRate=1000) public

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

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

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

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

    public ChatterBox chatterBox() { // Spring ensures return new ChatterBox(); // saySomething() method is } // called once per second }
  46. @Enable* benefits easy to see what's going on easy to

    write your own adapts smoothly from simple to sophisticated supported beyond core spring-framework e.g. spring-data's @EnableMongoRepositories
  47. code-based configuration is complete as of Spring Framework 3.1 can

    configure all major container features mix and match styles as desired
  48. familiar? <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>
  49. JPA

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

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

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

    emf.setDataSource(dataSource()); // scan classpath for JPA @Entity types emf.setPackagesToScan("com.foo.domain"); return emf; }
  53. <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>
  54. 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("/"); } }
  55. WebApplicationInitializer allows code-based config of servlet container builds on Servlet

    3's ServletContainerInitializer auto-detected on Servlet container startup
  56. *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. These new features just mean that if you don't want XML, you don't have to use it. That's all. kthx, bye.
  57. config style POJOs + 3rd party components ↓ @Configuration ┌─────────────────────┐

    + @Bean → │ the Spring container│ └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  58. config style POJOs + 3rd party components ↓ @Configuration ┌─────────────────────┐

    + @Bean → │ the Spring container│ + @Enable* └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  59. config style POJOs + 3rd party components (hybrid) ↓ <bean>

    + ┌─────────────────────┐ @Component + → │ the Spring container│ @Configuration └─────────────────────┘ ┌─────────────────────────┐ │ fully configured system │ │ ready for use │ └─────────────────────────┘
  60. recommendations go for 100% code-based config @Component + @Autowired for

    "your" components @Bean for third-party components @Enable to control framework features
  61. much more Environment and PropertySource APIs bean definition profiles testing

    support for @Configuration classes brand-new spring-scala project spring-integration Scala & Groovy DSLs
  62. check it out everything in this talk available in 3.1

    spring-framework 3.2 RC1 is now out a great time for feedback RC2 in a few weeks GA by year end