z, ? | toggle help (this) |
space, → | next slide |
shift-space, ← | previous slide |
d | toggle debug mode |
## <ret> | go to slide # |
c, t | table of contents (vi) |
f | toggle footer |
r | reload slides |
n | toggle notes |
p | run preshow |
Environment
APIEnvironment
APIorg.springframework.core.env.Environment
Environment
APIPropertySource
API.properties
filesPropertySource
APIEnvironment
maintains a hierarchy of PropertySources
StandardEnvironment
PropertySources
for:-D
flags)Standard
Servlet
Environment
PropertySources
for:-D
flags)Environment
to useApplicationContext
types now contain an Environment
Environment
PropertySources
ConfigurableEnvironment
API@PropertySource
annotationPropertySourcesPlaceholderConfigurer
3.1
PropertyPlaceholderConfigurer
${...}
placeholders via the Environment
<context:property-placeholder/>
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>
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 -->
@Inject
the Environment
@Configuration
public class DbConfig {
@Bean
public DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
return ds;
}
}
@Inject
the Environment
@Configuration
public class DbConfig {
@Bean
public DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
// configure and return the data source ...
return ds;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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;
}
}
@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
profiles
profiles
<beans>
<bean id="a" class="com.company.A"/>
<bean id="b" class="com.company.B"/>
<bean id="c" class="com.company.C"/>
</beans>
public static void main(String... args) {
GenericXmlApplicationContext ctx = new GXAC();
ctx.load("classpath:com/company/*-config.xml");
ctx.refresh();
ctx.getBean("a"); // ...
}
<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>
public static void main(String... args) {
GenericXmlApplicationContext ctx = new GXAC();
ctx.load("classpath:com/company/*-config.xml");
ctx.refresh();
ctx.getBean("a"); // ...
}
<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>
public static void main(String... args) {
GenericXmlApplicationContext ctx = new GXAC();
ctx.load("classpath:com/company/*-config.xml");
ctx.refresh();
ctx.getBean("a"); // ...
}
<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>
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
}
<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>
public static void main(String... args) {
GenericXmlApplicationContext ctx = new GXAC();
ctx.load("classpath:com/company/*-config.xml");
ctx.refresh();
ctx.getBean("a");
}
<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>
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");
}
<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>
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
}
<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="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/>
<beans>
<beans profile="dev">
</beans>
<beans profile="prod">
</beans>
</beans>
<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>
<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>
GenericApplicationContext ctx = ...;
ctx.getEnvironment().setActiveProfiles("dev");
ctx.refresh();
// ...
spring.profiles.active
-Dspring.profiles.active=p1,p2,p3
<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>
<web-app>
<servlet>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>p1,p2,p3</param-value>
</init-param>
</servlet>
<!-- ... -->
<web-app>
@Configuration
, completed@Configuration
class<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");
@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);
@Configuration
in Spring 3.0<beans>
</beans>
<beans>
<!-- scan for all @Component-annotated classes -->
<context:component-scan base-package="com.company"/>
</beans>
<beans>
<!-- scan for all @Component-annotated classes -->
<context:component-scan base-package="com.company"/>
<!-- handle any @Transactional annotations -->
<tx:annotation-driven/>
</beans>
<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>
<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>
@Enable*
annotations@Enable*
and @ComponentScan
<beans>
<context:component-scan base-package="com.company"/>
<tx:annotation-driven/>
<task:annotation-driven/>
<!-- ... -->
</beans>
@Configuration
@ComponentScan("com.company")
@EnableTransactionManagement
@EnableScheduling
public class AppConfig {
// ...
}
@Configuration
@ComponentScan("com.company") // ~= context:component-scan
@EnableTransactionManagement
@EnableScheduling
public class AppConfig {
// ...
}
@Configuration
@ComponentScan("com.company")
@EnableTransactionManagement // ~= tx:annotation-driven
@EnableScheduling
public class AppConfig {
// ...
}
@Configuration
@ComponentScan("com.company")
@EnableTransactionManagement
@EnableScheduling // ~= task:annotation-driven
public class AppConfig {
// ...
}
@Enable*
annotations@Profile
annotation<beans profile="..."/>
<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>
@Configuration
public class AbcConfig {
@Bean A a() { return new A(); }
@Bean B b() { return new B(); }
@Bean C c() { return new C(); }
}
@Configuration
@Profile("dev")
public class AbcConfig {
@Bean A a() { return new A(); }
@Bean B b() { return new B(); }
@Bean C c() { return new C(); }
}
@Configuration
support in TestContext framework@ContextConfiguration
and friends@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(locations="app-config.xml")
public class IntegrationTest {
@Autowired MyService myService;
@Test
public void testServiceMethods() {
// ...
}
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(locations="app-config.xml")
public class IntegrationTest {
@Autowired MyService myService; // inject a <bean>
@Test
public void testServiceMethods() {
// ...
}
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(locations="app-config.xml")
public class IntegrationTest {
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class IntegrationTest {
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class) // new in 3.1
public class IntegrationTest {
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class IntegrationTest {
@Autowired MyService myService;
@Test
public void testServiceMethods() {
// ...
}
}
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class IntegrationTest {
@Autowired MyService myService; // inject a @Bean
@Test
public void testServiceMethods() {
// ...
}
}
WebApplicationInitializer
WebApplicationInitializer
APIServletContainerInitializer
web.xml
entirely<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>
WebApplicationInitializer
equivalentpublic 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);
}
}
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);
}
}
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="..."
xsi:schemaLocation="..."
version="2.0">
<persistence-unit name="sample">
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
</properties>
</persistence-unit>
</persistence>
@Bean
public LocalContainerEntityManagerFactoryBean emf() {
LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPersistenceXmlLocation(
"classpath:META-INF/persistence.xml");
return emf;
}
@Bean
public LocalContainerEntityManagerFactoryBean emf() {
LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPersistenceXmlLocation(
"classpath:META-INF/persistence.xml"); // no more!
return emf;
}
@Bean
public LocalContainerEntityManagerFactoryBean emf() {
LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan("com.biz.app");
return emf;
}
@Bean
public LocalContainerEntityManagerFactoryBean emf() {
LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
// scan classpath for JPA @Entity types
emf.setPackagesToScan("com.biz.app");
return emf;
}
orm.hibernate4
packaging<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>
<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>
@Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataSource())
.addAnnotatedClasses(Person.class, Account.class)
.buildSessionFactory();
}
LocalSessionFactoryBuilder
Configuration
classorm.hibernate4
package@Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataSource())
.addAnnotatedClasses(Person.class, Account.class)
.buildSessionFactory();
}
@Bean
public PersistenceExceptionTranslator exTranslator() {
return new HibernateExceptionTranslator();
}
@Cacheable("books")
public Book findBook(ISBN isbn) {
return this.bookRepository.findBook(isbn);
}
@CacheEvict(value="books", allEntries=true)
public void loadBooks(InputStream batch) {
// ...
}
Cache
and CacheManager
SPIorg.springframework.cache
package<cache:*>
XML namespace@EnableCaching
annotation<cache:*>
namespace<cache:annotation-driven/>
<bean id="cacheManager"
class="org.sfwk.cache.support.SimpleCacheManager"/>
<property name="caches">
<bean class="org.sfwk...ConcurrentMapCacheFactoryBean">
<property name="name" value="books"/>
</bean>
</property>
</bean>
@EnableCaching
annotation@Configuration
@EnableCaching
class AppConfig {
@Bean
public CacheManager cacheManager() {
ConcurrentMapCacheManager mgr =
new ConcurrentMapCacheManager();
mgr.setCacheNames(Collections.singleton("books"));
return mgr;
}
}
HandlerMethod
-based approach@Validated
annotation supporting JSR-303 groups@Valid
support on @RequestBody
method args@EnableWebMvc
@rstoyanchev
's
spring-mvc-3.1-updateorm.hibernate4
packageLocalSessionFactoryBuilder
discussed earlierJobFactoryBean
et al.ResultSetExtractor
RowSetProvider
APIForkJoinPoolFactoryBean
c:
namespacep:
namespace (around since Spring 2.0)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;
}
}
<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>
<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>
<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>
$ git clone git@github.com/SpringSource/spring-framework.git
$ cd spring-framework
$ ./gradlew build
...
BUILD SUCCESSFUL
$ ./gradlew install
...
BUILD SUCCESSFUL