Professional Documents
Culture Documents
Who am I?
Java and Spring Fanatic Senior Engineer with SpringSource Spring Social Project Lead Author
The code is more what youd call guidelines than actual rules.
- Captain Hector Barbossa, Pirates of the Caribbean:The Curse of the Black Pearl
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
DispatcherServlet creates an application context So does ContextLoaderListener DispatcherServlet can see ContextLoaderListeners beans ContextLoaderListener cannot see DispatcherServlets beans Confusing, unnecessary, and complicates some things (security)
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Congure DispatcherServlet to load an empty context Congure ContextLoaderListener to load all beans
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <import resource="appServlet/servlet-context.xml" /> <import resource="neo4j-context.xml" /> <import resource="security.xml" /> <context:component-scan base-package="com.mouseguests" /> </beans>
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
@Configuration @Import({ MvcConfig.class, Neo4jConfig.class, SecurityConfig.class }) @ComponentScan(basePackages="example.config", excludeFilters={ @Filter(Configuration.class)} public class RootApplicationContext { }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
<beans ...> <bean id="foo" class="example.Foo"> <property name="bar" ref="bar" /> </bean> <bean id="bar" class="example.Bar"/> </beans>
Not type-safe
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
<beans ...> <bean id="foo" class="example.Foo"> <property name="bar" ref="bar" /> </bean> <bean id="bar" class="example.Bar"/> </beans>
Not refactor-friendly
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
<beans ...> <bean id="foo" class="example.Foo"> <property name="bar" ref="bar" /> </bean> <bean id="bar" class="example.Bar"/> </beans>
<beans ...> <bean id="foo" class="example.Foo"> <property name="bar" ref="bar" /> </bean> <bean id="bar" class="example.Bar"/> <bean .../> <bean .../> <bean .../> <bean .../> </beans>
Verbose
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Type-safe
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Still verbose?
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Smart Conguration
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Smart Conguration
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Smart Conguration
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
<tx:annotation-driven /> <mvc:annotation-driven /> <sched:annotation-driven /> <aop:aspectj-autoproxy /> <context:load-time-weaver />
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
@Enable Annotations
@Configuration @EnableWebMvc @EnableTransactionManagement @EnableScheduling @EnableAsync @EnableAspectJAutoProxy @EnableLoadTimeWeaving public class MyConfig { ... }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Oh yeah...component-scanning
...becomes...
@Configuration @ComponentScan("com.habuma") public class MyConfig { ... }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Component Scanning
<context:component-scan base-package="com.habuma" />
or
@ComponentScan("com.habuma")
Auto-wiring
Component-scanning also includes auto-wiring (by type)
@Component public class FooService { @Autowired public FooService(Bar bar) { ... } ... }
Component-scanning Controllers
<beans ...> <context:component-scan base-package="example" /> </beans>
or
@Configuration @ComponentScan("example") public class MvcConfig { ... }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
<bean id="dataSource" class="JdbcConnectionPool" factory-method="create" destroy-method="dispose"> <constructor-arg value="${database.url}" /> <constructor-arg value="${database.username}" /> <constructor-arg value="${database.password}" /> </bean>
Solution?
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Better Solution
@Configuration @Profile("dev") public class ProductionConfig { @Bean(destroyMethod="shutdown") public DataSource dataSource() { EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory(); ... } } @Configuration @Profile("qa") public class QAConfig { @Bean(destroyMethod="dispose") public DataSource dataSource() { return JdbcConnectionPool.create(...); } } @Configuration @Profile("production") public class ProductionConfig { public @Bean DataSource jndiDataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); ... } }
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Better Solution
<beans ...> <beans profile="dev"> <jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:schema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database> </beans> <beans profile="qa"> <bean id="dataSource" class="JdbcConnectionPool" factory-method="create" destroy-method="dispose"> <constructor-arg value="${database.url}" /> <constructor-arg value="${database.username}" /> <constructor-arg value="${database.password}" /> </bean> </beans> <beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDS" resource-ref="true" proxy-interface="javax.sql.DataSource" /> </beans> </beans>
Email: craig@habuma.com Twitter: @habuma Blog: http://www.springinaction.com Sample Code: http://github.com/habuma
Activating Proles
spring.profiles.active
and spring.profiles.default
In web.xml
<context-param> <param-name>spring.profiles.default</param-name> <param-value>development</param-value> </context-param> <servlet> <servlet-name>myApp</servlet-name> <servlet-class>org...DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.default</param-name> <param-value>development</param-value> </init-param> </servlet>
Consider using Spring Data JPA to create repositories instead of writing them yourself
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Gradle
dependencies { compile "org.springframework.data:spring-data-jpa:1.1.0.RELEASE" ... }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
By the way...
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Back to Step 3
public interface OrderRepository extends JpaRepository<Order, Long> { List<Order> findByCustomer(String customer); List<Order> findByCustomerLike(String customer); List<Order> findByCustomerAndType(String customer, String type); List<Order> findByCustomerLikeAndType(String customer, String type); @Query("select o from Order o " + "where o.customer = 'Chuck Wagon' and o.type = ?1") List<Order> findChucksOrders(String type); }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Two kinds of testing... Unit-testing (Spring-supported, not Spring-involved) Integration-testing (Spring-supported, Spring-involved)
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
@Test public void orderItems() { OrderRepository orderRepo = ...; // mock OrderRepository OrdersController controller = new OrdersController(orderRepo); ModelMap model = new ModelMap(); Assert.assertEquals("lineItems", controller.orderItems(12345L, model); List<LineItem> items = (List<LineItem>) model.asMap().get("lineItems"); Assert.assertEquals(5, items.size()); ... // more assertions }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
@Test public void orderItems() { OrderRepository orderRepo = ...; // mock OrderRepository OrdersController controller = new OrdersController(orderRepo); MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller); mockMvc.perform(get("/orders/12345/items")) .andExpect(view().name("lineItems")) .andExpect(model().attributeExists("lineItems")) .andExpect(...) // more assertions }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Gradle
dependencies { compile "org.springframework:spring-test-mvc:1.0.0.M1" ... }
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Email: craig@habuma.com
Twitter: @habuma
Blog: http://www.springinaction.com
Q &A