Responsive Ads Here

Monday, July 22, 2013

What’s New in Spring 3.1





What’s New in Spring 3.1


New in Spring 3.0


  • Java 5+
  • Spring Expression Language
  • New Spring MVC Features
    • REST
    • Ajax
    • Declarative Validation
  • Backwards compatible with Spring 2.5

Spring Expression Language

  • Unified EL++
    • Deferred evaluation of expressions
    • Support for expressions that can set values and invoke methods
    • Pluggable API for resolving Expressions
    • Unified Expression Language: http://is.gd/2xqF
    • Spring 3.0 allows usage in XML files and @Value annotations

REST Support


REST with @PathParam


http://myserver/myapp/show/123


@RequestMapping(method = RequestMethod.GET)
public User show(@PathParam Long id) {
return userManager.getUser(id);
}

REST with RestController

@Controller
public class ResumesController implements RestController<Resume, Long> {
GET http://myserver/myapp/resumes
public List<Resume> index() {}
POST http://myserver/myapp/resumes
public void create(Resume resume) {}
GET http://myserver/myapp/resumes/1
public Resume show(Long id) {}
DELETE http://myserver/myapp/resumes/1
public void delete(Long id) {}
PUT http://myserver/myapp/resumes/1
public void update(Resume resume) {}
}


Dropping Support For...

  • Commons Attributes
  • TopLink (EclipseLink instead)
  • MVC Controller hierarchy
  • Unit 3.8 Test classes

What’s New in Spring 3.1

  • Java 7 Support
  • Hibernate 4 Support
  • Servlet 3.0 Support
  • Cache Abstraction
  • Java Configuration
  • Environments and Profiles
  • Test Context Support for Configuration Classes and Profiles

Java 7 Support

  • Fork/join support
  • JDBC 4.1
    • Try-with-resources
    • RowSet 1.1
  • Multicatch and final rethrow
  • String in switch statement support

What’s New in Hibernate 4?

  • Move to Gradle for builds
  • SessionFactory building
  • Initial osgi-fication
  • Java 6 / JDBC 4 as baseline
  • Multi-tentant database support
  • Migration to i18n logging framework

Hibernate 3

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
</value>
<!-- Turn batching off for better error messages under PostgreSQL -->
<!-- hibernate.jdbc.batch_size=0 -->
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

Hibernate 4

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="hibernateExceptionTranslator"
class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
</value>
<!-- Turn batching off for better error messages under PostgreSQL -->
<!-- hibernate.jdbc.batch_size=0 -->
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

Spring + Hibernate 3

@Autowired
@Required
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public List<T> getAll() {
return hibernateTemplate.loadAll(this.persistentClass);
}
public T get(PK id) {
T entity = hibernateTemplate.get(this.persistentClass, id);
if (entity == null) {
log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");
throw new ObjectRetrievalFailureException(this.persistentClass, id);
}
return entity;
}
public T save(T object) {
return hibernateTemplate.merge(object);
}
public void remove(PK id) {
hibernateTemplate.delete(this.get(id));
}

Hibernate 4

@Autowired
@Required
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List<T> getAll() {
return sessionFactory.getCurrentSession().createQuery("from " + this.persistentClass).list();
}
public T get(PK id) {
T entity = (T) sessionFactory.getCurrentSession().get(this.persistentClass, id);
if (entity == null) {
log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");
throw new ObjectRetrievalFailureException(this.persistentClass, id);
}
return entity;
}
public T save(T object) {
return (T) sessionFactory.getCurrentSession().merge(object);
}
public void remove(PK id) {
sessionFactory.getCurrentSession().delete(this.get(id));
}

JPA with Spring 2.0


JPA with Spring 3.1

Spring Data

Spring Data makes it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services as well as provide improved support for relational database technologies.

http://www.springsource.org/spring-data 



Plain JPA :: Before

/**
* Service interface for {@link Customer}s.
*
* @author Oliver Gierke
*/
public interface CustomerService {
Customer findById(Long id);
Customer save(Customer customer);
List<Customer> findAll();
List<Customer> findAll(int page, int pageSize);
List<Customer> findByLastname(String lastname, int page, int pageSize);
}

/**
* Plain JPA implementation of {@link CustomerService}.
*
* @author Oliver Gierke
*/
@Repository
@Transactional(readOnly = true)
public class CustomerServiceImpl implements CustomerService {
@PersistenceContext
private EntityManager em;
@Override
public Customer findById(Long id) {
return em.find(Customer.class, id);
}
@Override
public List<Customer> findAll() {
return em.createQuery("select c from Customer c", Customer.class).getResultList();
}
@Override
@Transactional
public Customer save(Customer customer) {
if (customer.getId() == null) {
em.persist(customer);
return customer;
} else {
return em.merge(customer);
}
}


JPA with Spring Data :: After

/**
* Repository to manage {@link Customer} instances.
*
* @author Oliver Gierke
*/
public interface CustomerRepository extends
CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
Page<Customer> findByLastname(String lastname, Pageable pageable);
}

What’s New in Servlet 3.0

  • Programmatic definition of filters, servlets, listeners and URL patterns
    • @WebServlet, @WebFilter, @WebListener
    • @WebInitParam
    • @MultipartConfig
  • Web Fragments
  • Asynchronous Servlet and Comet Support

Hardest thing about Servlet 3?

Is getting the Maven dependency right ...


<!-- Servlet 3.0 -->
<!-- http://stackoverflow.com/questions/1979957/maven-dependency-for-servlet-3-0-api -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.servlet</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>

Spring + Servlet 3.0

  • WebApplicationInitializer for programmatic configuration
  • Instead of:

<servlet>
<servlet-name>kickstart</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>kickstart</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

Servlet 3.0

  • WebApplicationInitializer for programmatic configuration
  • You use:

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
public class KickstartWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet());
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.htm");
}
}

  • WebApplicationInitializer with XmlApplicationContext

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
public class KickstartWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/applicationContext.xml");
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet());
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.htm");
}
}

  • WebApplicationInitializer with JavaConfig

public class KickstartWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher",
new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}

@MVC Resources

<!-- View Resolver for JSPs -->
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<beans:property name="prefix" value="/WEB-INF/pages/"/>
<beans:property name="suffix" value=".jsp"/>
</beans:bean>
<beans:bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="messages"/>
<beans:property name="useCodeAsDefaultMessage" value="true"/>
</beans:bean>
<context:component-scan base-package="spring.kickstart"/>
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven/>
<resources mapping="/resources/**" location="/resources/"/>
<!-- Maps '/' requests to the 'index' view -->
<view-controller path="/" view-name="index"/>



<link rel="stylesheet" type="text/css"
href="${ctx}/resources/styles/deliciouslyblue/theme.css" title="default" />
<link rel="alternate stylesheet" type="text/css"
href="${ctx}/resources/styles/deliciouslygreen/theme.css" title="green" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="${ctx}/resources/scripts/application.js"></script>


Web Performance Best Practices

  • Optimizing caching
  • Minimizing round-trip times
  • Minimizing request overhead
  • Minimizing payload size
  • Optimizing browser rendering
  • Optimizing for mobile

Wro4j

  • Open Source Java project for optimization of web resources
  • Provides concatenation and minimization of JS and CSS 
  • Gzip, YUI Compressor, JsHint, JsHint, CssLint, LESS, SASS, CoffeeScript, Dojo Shrinksafe

Profiles



XML Profiles

  • Profiles allow for environment-specific bean definitions
  • Activated with:
    • -Dspring.profiles.active=test
    • ctx.getEnvironment().setActiveProfiles(“dev”)
    • <init-param> spring.profiles.active in web.xml
    • @Profile(“prod”) with @Configuration

Wro4j and Profiles





@Profile

import org.springframework.context.annotation.Profile;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("dev")
public @interface Dev {
}
@Repository
@Dev
@Transactional(readOnly = true)
public class CustomerRepositoryImpl implements CustomerRepository {
@PersistenceContext
private EntityManager em;

Cache Abstraction

  • Not an implementation, but an abstraction
  • Frees you from writing logic, but does not provide stores
    • JDK ConcurrentMap
    • EhCache
  • @Cacheable and @CacheEvict
  • Can use Spring EL for “key” and “condition” attributes
  • Annotations triggered by <cache:annotation-driven/>

Test Support for JavaConfig and Profiles

  • Spring 3.0 added @Configuration (JavaConfig)
  • TestContext Framework provides annotationdriven testing support
  • Spring 3.1 adds “loader” attribute to @ContextConfiguration for @Configuration

Spring 2.0 Testing


public class CustomerRepositoryTest extends AbstractJpaTests {
private CustomerRepository customerRepository;
private EntityManagerFactory emf;
public void setCustomerRepository(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
protected String[] getConfigLocations() {
return new String[] {"repository-test-config.xml"};
}
protected void onSetUpInTransaction() throws Exception {
EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);
Customer c = new Customer();
c.setName("Test");
c.setCustomerSince(new Date());
em.persist(c);
super.onSetUpInTransaction();
}
public void testAddCustomer() {
Customer c = new Customer();
...

TestContext with XML

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/repository-config.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class CustomerRepositoryTest {
@PersistenceContext
private EntityManager em;
@Autowired
private CustomerRepository customerRepository;
@Before
@Transactional
public void onSetUpInTransaction() {
Customer c = new Customer();
c.setName("Test");
c.setCustomerSince(new Date());
em.persist(c);
}
@Test
public void testAddCustomer() {
Customer c = new Customer();
c.setName("New");
c.setCustomerSince(new Date());
customerRepository.save(c);
List<Customer> customers = customerRepository.findAll();
assertTrue(customers.contains(c));
}

TestContext with @Configuration

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@Transactional
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class CustomerRepositoryTest {
@Configuration
static class ContextConfiguration {
@Bean
public CustomerRepository customerRepository() {
return new CustomerRepositoryImpl();
}
}
@PersistenceContext
private EntityManager em;
@Autowired
private CustomerRepository customerRepository;
@Before
@Transactional
public void onSetUpInTransaction() {
Customer c = new Customer();
c.setName("Test");
c.setCustomerSince(new Date());
em.persist(c);
}
@Test
public void testAddCustomer() {
Customer c = new Customer();

No comments:

Post a Comment