Suresh Rohan's Blog

This blog is all about Java, J2EE,Spring, Angular, React JS, NoSQL, Microservices, DevOps, BigData, Tutorials, Tips, Best practice, Interview questions, Views, News, Articles, Techniques, Code Samples, Reference Application and much more

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