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
/**
* 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