220 likes | 366 Vues
In this comprehensive presentation, Kristoffer Moum, an experienced systems developer, provides insights into developing web applications using the Spring Framework. Attendees will gain a clear understanding of setting up a Spring development environment, including configuration, interceptor chaining, Aspect-Oriented Programming (AOP), and integrating Spring with Hibernate and JDBC. The session covers essential components, web application configuration, practical examples, and testing strategies to ensure efficient development cycles, making it an invaluable resource for aspiring Spring developers.
E N D
whoami • Kristoffer Moum • Systems Developer and consultant at Objectware • Five years of experience with Java/J2EE
Agenda • Presentation goals • Development environment setup • Configuration • Spring and MVC • Basics of testing • Interceptor chaining • Aspect Oriented Programming (AOP) examples • Spring and Hibernate • Spring and JDBC • Summary
Presentation goals • A better understanding of the Spring framework targetted on web applications • Knowledge to setup a development environment with Spring, including method interceptors/AOP and a persistence layer
Development environment setup • Required components • JDK 1.5 • A Servlet / JSP container, i.e. Tomcat • Exploded war-file for fast test and deploy cycles • All tiers cannot be tested automatically in a sensible way
Web application configuration • Web application configuration • web.xml • Spring container configuration • Various xml configuration files
Example web.xml <web-app> <display-name>springwebexample</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/spring.xml</param-value> </context-param> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springapp</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
Example spring.xml <bean id="customerDao" class="no.objectware.jz2005.springwebapp.dao.impl.HibernateCustomerDao"> <property name="sessionFactory"><ref local="sessionFactory" /></property> </bean> <bean id="customerTarget" class="no.objectware.jz2005.springwebapp.service.impl.DefaultCustomerService"> <property name="customerDao"><ref bean="customerDao" /></property> </bean> <bean id="timingInterceptor" class="no.objectware.jz2005.springwebapp.aop.TimingInterceptor"/> <bean id="timeoutInterceptor" class="no.objectware.jz2005.springwebapp.aop.TimeoutInterceptor"/> <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"><ref local="sessionFactory" /></property> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager" /> </property> <property name="transactionAttributeSource"> <value>no.objectware.jz2005.springwebapp.service.CustomerService.save*=PROPAGATION_REQUIRED,-Exception</value> </property> </bean> <bean id="customerService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>no.objectware.jz2005.springwebapp.service.CustomerService</value> </property> <property name="interceptorNames"> <list> <value>timingInterceptor</value> <value>timeoutInterceptor</value> <value>transactionInterceptor</value> <value>customerTarget</value> </list> </property> </bean>
Spring and MVC – example Controller public class ProductsController extends SimpleFormController { private ProductService productService; public void setProductService(ProductService productService){ this.productService = productService; } public ProductsController() { } protected ModelAndView onSubmit(Object command, BindException errors) throws Exception { List<Product> products = productService.findAllProducts(); return new ModelAndView(getSuccessView(),"products", products); } }
Spring and MVC – example configuration <bean id="productsForm" class="no.objectware.jz2005.springwebapp.web.controller.ProductsController"> <property name="productService"> <ref bean="productService"/> </property> <property name="formView"> <value>displayProducts</value> </property> <property name="successView"> <value>displayProductDetails</value> </property> <property name="validator"> <bean class="no.objectware.jz2005.springwebapp.web.validator.ProductValidator"/> </property> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/products.html">productsForm</prop> </props> </property> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean>
Spring and MVC • Several abstract Controller implementations • Validation through Validator interface • Binding to form fields through <spring:bind>
Basics of testing • Unit testing • Integration testing • Rolling back transactions • AbstractDependencyInjectionSpringContextTests • Hibernate laziness • Mock classes within the framework
Interceptor chaining and AOP • Interceptor chaining by declarative configuration • How to make it useful • The good old invocation timing example • Implement time-out handling • Where to apply it • Write Once Read Many • Infrastructure
AOP examples • Caching time-consuming look-ups • Caching by declarative configuration • Business interface remains unchanged • Application security • Declarative security handling • The Acegi framework • Method invocation time-out handling
Business method invocation timeout public final class ReadOnlyTimeoutInterceptor implements MethodInterceptor { private static ExecutorService runner = Executors.newCachedThreadPool(); private Map<String,String> timeouts = new HashMap<String,String>(); public void setTimeouts(Map<String, String> timeouts) { this.timeouts = timeouts; } public Object invoke(MethodInvocation invocation) throws Throwable{ String serviceMethod = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName(); String maxInvocation = timeouts.get(serviceMethod); if(maxInvocation == null) { maxInvocation = timeouts.get("default"); } Future asyncCaller = runner.submit(new CallableHandler(invocation, serviceMethod)); try { return asyncCaller.get(Long.parseLong(maxInvocation), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { throw e.getCause(); } catch (TimeoutException e) { throw new RuntimeException("Service [" + serviceMethod + "] timed out after approximately [" + maxInvocation + "] ms"); } } (..)
Business method invocation timeout (cont.) public class CallableHandler implements Callable { private MethodInvocation invocation; private String service; public QualityOfServiceHandler(MethodInvocation invocation, String service) { this.invocation = invocation; this.service = service; } public Object call() throws Exception { try { return invocation.proceed(); } catch (Throwable throwable) { throw new RuntimeException("Exception when invoking service [" + service + "]"); } } } }
Spring and Hibernate • Small amount of code • Extend HibernateDaoSupport • No handling of checked exceptions • Avoiding the dreaded LazyInitializationException
Spring and Hibernate by example public interface CustomerService { void save(Customer customer); } public final class DefaultCustomerService implements CustomerService { private CustomerDao customerDao; public void setCustomerDao(CustomerDao customerDao) { this.customerDao = customerDao; } public void save(Customer customer) { customerDao.save(customer); } } public interface CustomerDao { void save(Customer customer); } public final class HibernateCustomerDao extends HibernateDaoSupport implements CustomerDao { public void save(Customer customer) { getHibernateTemplate().save(customer); } }
Spring and Jdbc • Still a small amount of code • Extend JdbcDaoSupport • When to apply this wrapper • Joining many tables with lazy collections isn’t exactly fast • Databases could be out of our control, i.e. Legacy and may have lots of constraints
Spring and Jdbc by example public final class JdbcProductCategoryDao extends JdbcDaoSupport implements ProductCategoryDao { private static final String findAllProductCategories = "select * from product_category"; public List<ProductCategory> findAll() { return getJdbcTemplate().query(findAllProductCategories, new ProductCategoryRowMapper()); } public static class ProductCategoryRowMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) throws SQLException { long categoryId = rs.getLong("product_category_id"); String description = rs.getString("product_category_desc"); return new ProductCategory(categoryId, description); } } }
Summary • Development environment setup • Configuration • Spring and MVC • Basics of testing • Interceptor chaining • Aspect Oriented Programming (AOP) examples • Spring and Hibernate • Spring and JDBC
Further reading • Introduction to Dependency Injection • http://www.martinfowler.com/articles/injection.html • Introduction to Spring • http://www.theserverside.com/articles/article.tss?l=SpringFramework • Spring Forum • http://forum.springframework.org • Blog on Hibernate and laziness in different application tiers • http://jroller.com/comments/kbaum/Weblog/orm_lazy_initialization_with_dao • The Serverside discussion thread on testing • http://theserverside.com/news/thread.tss?thread_id=33215 • Matt Raible’s appfuse project