Slide 1

Slide 1 text

Introducing Spring JavaConfig Chris Beams Senior Consultant Lead, Spring JavaConfig SpringSource December 1-4, 2008 at the Westin Diplomat, Hollywood, FL, USA

Slide 2

Slide 2 text

Goal

Slide 3

Slide 3 text

From

Slide 4

Slide 4 text

To @Bean

Slide 5

Slide 5 text

SpringSource Confidential. Do not distribute without express permission A bit about me •Senior Consultant with SpringSource •Project Lead, Spring JavaConfig •Trained 100’s of developers on Spring

Slide 6

Slide 6 text

SpringSource Confidential. Do not distribute without express permission A bit about you (how presumptuous!) •You’re someone who... •Knows something about •Dabbled in Spring 2.5’s @DI (@Autowired) •Really likes type-safety •Wants to work in pure Java!

Slide 7

Slide 7 text

Elevator Pitch

Slide 8

Slide 8 text

Spring JavaConfig provides the full power of the Spring DI container... ...with the familiarity, ease, and refactorable type-safety of pure Java.

Slide 9

Slide 9 text

Which means

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

But wait... is Spring’s really so bad?

Slide 12

Slide 12 text

SpringSource Confidential. Do not distribute without express permission Spring IDE http://springide.org

Slide 13

Slide 13 text

SpringSource Confidential. Do not distribute without express permission SpringSource Tool Suite •Adds XML intelligence beyond the features in Spring IDE •Especially useful for large teams http://springsource.com/products/sts

Slide 14

Slide 14 text

SpringSource Confidential. Do not distribute without express permission And all the other major IDEs...

Slide 15

Slide 15 text

SpringSource Confidential. Do not distribute without express permission Namespaces hide XML plumbing • Spring 2.0 brought namespaces to the party, taking us from: • To:

Slide 16

Slide 16 text

SpringSource Confidential. Do not distribute without express permission Namespaces hide XML plumbing • And from: • To:

Slide 17

Slide 17 text

SpringSource Confidential. Do not distribute without express permission Maybe XML 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...

Slide 18

Slide 18 text

"strings"

Slide 19

Slide 19 text

SpringSource Confidential. Do not distribute without express permission Strings considered harmful getBean("foo") == + "strings" !=

Slide 20

Slide 20 text

(Casting)

Slide 21

Slide 21 text

SpringSource Confidential. Do not distribute without express permission An anti-refactoring twofer Foo foo = (Foo)context.getBean("foo");

Slide 22

Slide 22 text

SpringSource Confidential. Do not distribute without express permission Ahh... that’s better Foo foo = context.getBean(Foo.class);

Slide 23

Slide 23 text

SpringSource Confidential. Do not distribute without express permission As type-safe as it gets • JavaConfig takes full advantage of Java 5.0’s generics to avoid the pitfalls of "strings" and (casting).

Slide 24

Slide 24 text

SpringSource Confidential. Do not distribute without express permission All Java, all the time • Spring XML may be much easier to deal with today • but... • if we could do it all in Java, why wouldn’t we?

Slide 25

Slide 25 text

It’s all about metadata

Slide 26

Slide 26 text

SpringSource Confidential. Do not distribute without express permission @nnotations make JavaConfig possible @Bean OrderProcessor orderProcessor() { ... }

Slide 27

Slide 27 text

SpringSource Confidential. Do not distribute without express permission @Bean == @Bean(scope=PROTOTYPE, primary=TRUE) OrderProcessor orderProcessor() { ... }

Slide 28

Slide 28 text

SpringSource Confidential. Do not distribute without express permission @Configuration == @Configuration(defaultLazy=TRUE) public class AppConfig { public @Bean OrderProcessor orderProcessor() { ... } }

Slide 29

Slide 29 text

Time to bootstrap

Slide 30

Slide 30 text

SpringSource Confidential. Do not distribute without express permission Enter JavaConfigApplicationContext ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml"); TransferService service = (TransferService) ctx.getBean("transferService"); service.transfer(50.00, "1", "2"); JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(AppConfig.class); TransferService service = ctx.getBean(TransferService.class); service.transfer(50.00, "1", "2");

Slide 31

Slide 31 text

DEMO Configuring the Spring container with JavaConfig

Slide 32

Slide 32 text

Refs and Values

Slide 33

Slide 33 text

SpringSource Confidential. Do not distribute without express permission Inter-bean references @Bean public OrderProcessor orderProcessor() { return new OrderProcessor(orderRepository()); } @Bean public OrderRepository orderRepository() { return new JdbcOrderRepository(dataSource()); }

Slide 34

Slide 34 text

SpringSource Confidential. Do not distribute without express permission Q: What 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!

Slide 35

Slide 35 text

SpringSource Confidential. Do not distribute without express permission A: Externalize ‘em! db.url="jdbc:hsqldb:hsql://localhost:9001" db.user="sa" db.pass="" com/acme/db.properties: @Configuration @PropertiesValueSource("classpath:com/acme/db.properties") public class DataConfig { private @ExternalValue("db.url") String url; private @ExternalValue("db.user") String username; private @ExternalValue("db.pass") String password; @Bean public DataSource dataSource() { jdbcDataSource ds = new jdbcDataSource(); ds.setDatabase(url); ds.setUser(username); ds.setPassword(password); return ds; } }

Slide 36

Slide 36 text

SpringSource Confidential. Do not distribute without express permission Multiple value sources @ExternalValue @PropertiesValueSource @SystemPropertiesValueSource @EnvironmentValueSource

Slide 37

Slide 37 text

Let’s get @Transactional

Slide 38

Slide 38 text

SpringSource Confidential. Do not distribute without express permission Enabling @Transactional via XML 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

Slide 39

Slide 39 text

SpringSource Confidential. Do not distribute without express permission Enabling @Transactional 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

Slide 40

Slide 40 text

@Aspect-oriented

Slide 41

Slide 41 text

SpringSource Confidential. Do not distribute without express permission An @Aspect, applied with XML 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'

Slide 42

Slide 42 text

SpringSource Confidential. Do not distribute without express permission An @Aspect, 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

Slide 43

Slide 43 text

Mix it up

Slide 44

Slide 44 text

SpringSource Confidential. Do not distribute without express permission Plays nicely with others @Bean + @DI @Bean +

Slide 45

Slide 45 text

SpringSource Confidential. Do not distribute without express permission Bootstrapping @DI with XML package com.bank.services; @Service public class TransferService { private final AccountRepository accountRepository; @Autowired public TransferService(AccountRepository accountRepository) { this.accountRepository = accountRepository; } public void transfer(double amt, String srcAcctId, String destAcctId) { ... } } ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml"); TransferService service = (TransferService) ctx.getBean("transferService"); service.transfer(50.00d, "A123", "C456"); app-config.xml

Slide 46

Slide 46 text

SpringSource Confidential. Do not distribute without express permission Bootstrapping @DI 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) { ... } }

Slide 47

Slide 47 text

SpringSource Confidential. Do not distribute without express permission An @Autowired @Configuration @Configuration @ComponentScan("com.bank.dataaccess") public class AppConfig { private @Autowired AccountRepository accountRepository; public @Bean TransferService transferService() { return new TransferService(accountRepository); } } JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(AppConfig.class); TransferService service = ctx.getBean(TransferService.class); service.transfer(50.00d, "A123", "C456"); Scans and injects @Repository-annotated JdbcAccountRepository bean package com.bank.dataaccess; @Repository public class JdbcAccountRepository { ... }

Slide 48

Slide 48 text

SpringSource Confidential. Do not distribute without express permission JavaConfig <-> @DI integration is seamless • @AnnotationDrivenConfig • Enables processing of • @Autowired • JSR-250 annos @PostConstruct, @PreDestroy, @Resource.. • Is the exact analog of • @ComponentScan • Enables @AnnotationDrivenConfig functionality implicitly • Scans packages for @Component-(meta-)annotated classes • Is the exact analog of • @Configuration classes are subject to being @Autowire’d too!

Slide 49

Slide 49 text

SpringSource Confidential. Do not distribute without express permission Plays nicely with others @Bean + @DI @Bean +

Slide 50

Slide 50 text

SpringSource Confidential. Do not distribute without express permission Bootstrapping JavaConfig from XML package com.bank; @Configuration public class DataAccessConfig { public @Bean AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource()); } } ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml"); TransferService service = (TransferService) ctx.getBean("transferService"); service.transfer(50.00d, "A123", "C456"); app-config.xml

Slide 51

Slide 51 text

SpringSource Confidential. Do not distribute without express permission Bootstrapping XML from JavaConfig @Configuration @ImportXml(locations="classpath:com/bank/data-access-config.xml") @AnnotationDrivenInjection public class AppConfig { private @Autowired AccountRepository accountRepository; @Bean public TransferService transferService() { return new TransferService(accountRepository); } } ctx = new JavaConfigApplicationContext(AppConfig.class); TransferService service = ctx.getBean(TransferService.class); service.transfer(50.00d, "A123", "C456"); com/bank/data-access-config.xml

Slide 52

Slide 52 text

SpringSource Confidential. Do not distribute without express permission JavaConfig <-> 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

Slide 53

Slide 53 text

Modularize

Slide 54

Slide 54 text

SpringSource Confidential. Do not distribute without express permission Splitting up @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!

Slide 55

Slide 55 text

SpringSource Confidential. Do not distribute without express permission Remember: @Configurations 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);

Slide 56

Slide 56 text

SpringSource Confidential. Do not distribute without express permission Preferred approach @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

Slide 57

Slide 57 text

SpringSource Confidential. Do not distribute without express permission @Import @Configuration 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);

Slide 58

Slide 58 text

SpringSource Confidential. Do not distribute without express permission Rich support 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 •Autowire @Configuration beans for best effect •More refactorable •Easier navigation / discoverability

Slide 59

Slide 59 text

What about webapps?

Slide 60

Slide 60 text

SpringSource Confidential. Do not distribute without express permission The usual approach contextConfigLocation /WEB-INF/application-config.xml org.springframework.web.context.ContextLoaderListener JVM Servlet Container

Slide 61

Slide 61 text

SpringSource Confidential. Do not distribute without express permission First-class support for web applications contextClass org.springframework.config.java.context.JavaConfigWebApplicationContext JVM Servlet Container contextConfigLocation org.spring...ContextLoaderListener com.foo.AppConfig @Bean @Bean @Bean

Slide 62

Slide 62 text

DEMO Converting Spring’s PetClinic application from XML configuration to JavaConfig

Slide 63

Slide 63 text

Roadmap

Slide 64

Slide 64 text

SpringSource Confidential. Do not distribute without express permission Short-term •JavaConfig 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

Slide 65

Slide 65 text

Summary

Slide 66

Slide 66 text

SpringSource Confidential. Do not distribute without express permission Summary • 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

Slide 67

Slide 67 text

Q&A

Slide 68

Slide 68 text

Thank you! [email protected] http://springframework.org/javaconfig http://twitter.com/javaconfig