about you (how presumptuous!) •You’re someone who... •Knows something about <beans/> •Dabbled in Spring 2.5’s @DI (@Autowired) •Really likes type-safety •Wants to work in pure Java!
XML plumbing • Spring 2.0 brought namespaces to the party, taking us from: <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:application.properties"/> </bean> • To: <context:property-placeholder location="classpath:application.properties"/>
ain’t so bad after all... • IDE Tooling for Spring XML rocks • Namespaces dramatically improve the Spring XML landscape • More expressive, less verbose • Just ask Spring Security where it’s 200+ lines of config went! • But, XML does still leave a few things to be desired...
to do with literal values? @Bean public OrderRepository orderRepository() { return new JdbcOrderRepository(dataSource()); } @Bean public DataSource dataSource() { jdbcDataSource ds = new jdbcDataSource(); ds.setDatabase("jdbc:hsqldb:hsql://localhost:9001"); ds.setUser("sa"); ds.setPassword(""); return ds; } Hmm... No! No! No!
via XML <bean id="transferService" class="com.bank.TransferServiceImpl"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven/> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml"); TransferService service = (TransferService) ctx.getBean("transferService"); service.transfer(50.00, "A123", "C456"); public class TransferServiceImpl implements TransferService { @Transactional public void transfer(double amt, String srcAcctId, String destAcctId) { // transfer amt from src account to dest } } bean is a Spring-generated transactional proxy
via JavaConfig @Configuration @AnnotationDrivenTx public class AppConfig { @Bean TransferService transferService() { ... } @Bean DataSource dataSource() { ... } @Bean DataSourceTransactionManager transactionManager() { ... } } ctx = new JavaConfigApplicationContext(AppConfig.class); TransferService service = ctx.getBean(TransferService.class); service.transfer(50.00, "A123", "C456"); bean is a Spring-generated transactional proxy public class TransferServiceImpl implements TransferService { @Transactional public void transfer(double amt, String srcAcctId, String destAcctId) { // transfer amt from src account to dest } } Performs the same function as <tx:annotation-driven/>
applied with XML <aop:aspectj-autoproxy/> <bean class="com.acme.PropertyChangeTracker"/> <bean id="foo" class="com.acme.Foo"/> ctx = new ClassPathXmlApplicationContext("app-config.xml"); Foo foo = ctx.getBean("foo"); foo.setCacheSize(100); @Aspect public class PropertyChangeTracker { @Before("execution(void set*(*)) && target(obj) && args(value)") public void trackChange(JoinPoint jp, Object obj, Object value) { logger.info(format("%s property about to change to '%s' on object '%s'", jp.getSignature().getName(), value, obj)); } } bean is a Spring-generated AOP proxy INFO setCacheSize about to change to '100' on object 'foo'
applied with JavaConfig @Configuration @AspectJAutoProxy public class AppConfig { @Bean PropertyChangeTracker propertyChangeTracker() { ... } @Bean Foo foo() { ... } } ctx = new JavaConfigApplicationContext(AppConfig.class); Foo foo = ctx.getBean(Foo.class); foo.setCacheSize(100); @Aspect public class PropertyChangeTracker { @Before("execution(void set*(*)) && target(obj) && args(value)") public void trackChange(JoinPoint jp, Object obj, Object value) { logger.info(format("%s property about to change to '%s' on object '%s'", jp.getSignature().getName(), value, obj)); } } bean is a Spring-generated AOP proxy INFO setCacheSize about to change to '100' on object 'foo' Detects any beans that are @Aspect-annotated. Performs same function as <aop:aspectj-autoproxy/>
with JavaConfig @Configuration @ComponentScan("com.bank.services") public class AppConfig { @Bean public AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource()); } } ctx = new JavaConfigApplicationContext(AppConfig.class); TransferService service = ctx.getBean(TransferService.class); service.transfer(50.00d, "A123", "C456"); Scans @Service-annotated TransferService bean Gets injected into TransferService’s @Autowired constructor package com.bank.services; @Service public class TransferService { public @Autowired TransferService(AccountRepository accountRepository) { ... } }
@DI integration is seamless • @AnnotationDrivenConfig • Enables processing of • @Autowired • JSR-250 annos @PostConstruct, @PreDestroy, @Resource.. • Is the exact analog of <context:annotation-config/> • @ComponentScan • Enables @AnnotationDrivenConfig functionality implicitly • Scans packages for @Component-(meta-)annotated classes • Is the exact analog of <context:component-scan/> • @Configuration classes are subject to being @Autowire’d too!
XML integration is seamless • ConfigurationPostProcessor • Allows for bootstrapping JavaConfig from XML • A Spring BeanPostProcessor • Detects any beans that are @Configuration classes • Registers as beans the objects returned from @Bean methods • May have its own namespace support in the future • @ImportXml • Allows for bootstrapping XML from JavaConfig • Perfect for incremental migration to JavaConfig
@Bean methods across classes @Configuration public class DataSourceConfig { @Bean public DataSource dataSource() { // create and return a JDBC DataSource } } @Configuration public class RepositoryConfig { @Bean public AccountRepository accountRepository() { return new AccountRepository(dataSource()); } } Wants to reference the DataSourceConfig.dataSource() @Bean method, but can’t!
can be @Autowired! @Configuration public class DataSourceConfig { @Bean public DataSource dataSource() { // create and return a JDBC DataSource } } @Configuration @AnnotationDrivenConfig public class RepositoryConfig { @Autowired private DataSource dataSource; @Bean public AccountRepository accountRepository() { return new AccountRepository(dataSource); } } new JavaConfigApplicationContext(RepositoryConfig.class, DataSourceConfig.class);
@Configuration public class DataSourceConfig { @Bean public DataSource dataSource() { // create and return a JDBC DataSource } } @Configuration @AnnotationDrivenConfig public class RepositoryConfig { @Autowired private DataSourceConfig dataSourceConfig; @Bean public AccountRepository accountRepository() { return new AccountRepository(dataSourceConfig.dataSource()); } } new JavaConfigApplicationContext(RepositoryConfig.class, DataSourceConfig.class); •100% refactorable •Easy navigation within the IDE
public class DataSourceConfig { @Bean public DataSource dataSource() { // create and return a JDBC DataSource } } @Configuration @Import(DataSourceConfig.class) @AnnotationDrivenConfig public class RepositoryConfig { @Autowired DataSourceConfig dataSourceConfig; @Bean public AccountRepository accountRepository() { return new AccountRepository(dataSourceConfig.dataSource()); } } @Import informs JavaConfig about DataSourceConfig... ...so we only need to specify one @Configuration class when creating the context new JavaConfigApplicationContext(RepositoryConfig.class);
for modular @Configurations •JavaConfig builds on @DI for it’s approach to modularity •Use @Autowired, @AnnotationDrivenConfig •JavaConfigApplicationContext •Allows for passing multiple @Configuration classes to constructor •@Import •Allows for composition of @Configuration classes •Analogous to <import/> •Autowire @Configuration beans for best effect •More refactorable •Easier navigation / discoverability
is released at Milestone 4 (1.0.0.M4) •Work is underway on M5 •M5 will track Spring 3.0 •Spring 3.0 will include core elements of JavaConfig •JavaConfig 1.0 GA will release with (or shortly after) Spring 3.0 GA
JavaConfig allows for pure-Java, 100% XML-free configuration • No more (casting), no more "strings" • Works seamlessly with other configuration styles • Declarative support for transaction management, AOP, JMX & more • First-class support for web application development • Object-oriented configuration allows for new possibilities • Open for extension • The future looks bright for JavaConfig! • Integration into Spring 3.0