Time Travelling with Spring

This article by Sujoy Acharya, the author of the book Mockito for Spring, delves into the details Time Travelling with Spring. Spring 4.0 is the Java 8-enabled latest release of the Spring Framework. In this article, we'll discover the major changes in the Spring 4.x release and the four important features of the Spring 4 framework. We will cover the following topics in depth:

  • @RestController
  • AsyncRestTemplate
  • Async tasks
  • Caching

(For more resources related to this topic, see here.)

Discovering the new Spring release

This section deals with the new features and enhancements in Spring Framework 4.0. The following are the features:

  • Spring 4 supports Java 8 features such as Java lambda expressions and java.time. Spring 4 supports JDK 6 as the minimum.
  • All deprecated packages/methods are removed.
  • Java Enterprise Edition 6 or 7 are the base of Spring 4, which is based on JPA 2 and Servlet 3.0.
  • Bean configuration using the Groovy DSL is supported in Spring Framework 4.0.
  • Hibernate 4.3 is supported by Spring 4.
  • Custom annotations are supported in Spring 4.
  • Autowired lists and arrays can be ordered. The @Order annotation and the Ordered interface are supported.
  • The @Lazy annotation can now be used on injection points as well as on the @Bean definitions.
  • For the REST application, Spring 4 provides a new @RestController annotation. We will discuss this in detail in the following section.
  • The AsyncRestTemplate feature (class) is added for asynchronous REST client development.
  • Different time zones are supported in Spring 4.0.
  • New spring-websocket and spring-messaging modules have been added.
  • The SocketUtils class is added to examine the free TCP and UDP server ports on localhost.
  • All the mocks under the org.springframework.mock.web package are now based on the Servlet 3.0 specification.
  • Spring supports JCache annotations and new improvements have been made in caching.
  • The @Conditional annotation has been added to conditionally enable or disable an @Configuration class or even individual @Bean methods.
  • In the test module, SQL script execution can now be configured declaratively via the new @Sql and @SqlConfig annotations on a per-class or per-method basis.

You can visit the Spring Framework reference at http://docs.spring.io/spring/docs/4.1.2.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#spring-whats-new for more details.

Also, you can watch a video at http://zeroturnaround.com/rebellabs/spring-4-on-java-8-geekout-2013-video/ for more details on the changes in Spring 4.

Working with asynchronous tasks

Java 7 has a feature called Future. Futures let you retrieve the result of an asynchronous operation at a later time. The FutureTask class runs in a separate thread, which allows you to perform non-blocking asynchronous operations. Spring provides an @Async annotation to make it more easier to use. We'll explore Java's Future feature and Spring's @Async declarative approach:

  1. Create a project, TimeTravellingWithSpring, and add a package, com.packt.async.
  2. We'll exercise a bank's use case, where an automated job will run and settle loan accounts. It will also find all the defaulters who haven't paid the loan EMI for a month and then send an SMS to their number. The job takes time to process thousands of accounts, so it will be good if we can send SMSes asynchronously to minimize the burden of the job. We'll create a service class to represent the job, as shown in the following code snippet:
    @Service
    public class AccountJob {
       @Autowired
       private SMSTask smsTask;

       public void process() throws InterruptedException,
             ExecutionException {
    System.out.println("Going to find defaulters... ");

    Future<Boolean> asyncResult =smsTask.send("1", "2", "3");
    System.out.println("Defaulter Job Complete. SMS will be
               sent to all defaulter");

    Boolean result = asyncResult.get();
    System.out.println("Was SMS sent? " + result);
     }
    }

    The job class autowires an SMSTask class and invokes the send method with phone numbers. The send method is executed asynchronously and Future is returned. When the job calls the get() method on Future, a result is returned. If the result is not processed before the get() method invocation, the ExecutionException is thrown. We can use a timeout version of the get() method.

  3. Create the SMSTask class in the com.packt.async package with the following details:
    @Component
    public class SMSTask {
    @Async
    public Future<Boolean> send(String... numbers) {
    System.out.println("Selecting SMS format ");

    try {
       Thread.sleep(2000);
    } catch (InterruptedException e) {
         e.printStackTrace();
         return new AsyncResult<>(false);
    }
    System.out.println("Async SMS send task is Complete!!!");
    return new AsyncResult<>(true);
     }
    }

    Note that the method returns Future, and the method is annotated with @Async to signify asynchronous processing.

  4. Create a JUnit test to verify asynchronous processing:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:com/packt/async/
             applicationContext.xml")
    public class AsyncTaskExecutionTest {

    @Autowired ApplicationContext context;

    @Test
    public void jobTest() throws Exception {
       AccountJob job =
             (AccountJob)context.getBean(AccountJob.class);
       job.process();
     }
    }

    The job bean is retrieved from the applicationContext file and then the process method is called. When we execute the test, the following output is displayed:

    Going to find defaulters...
    Defaulter Job Complete. SMS will be sent to all defaulter
    Selecting SMS format
    Async SMS send task is Complete!!!
    Was SMS sent? true

    During execution, you might feel that the async task is executed after a delay of 2 seconds as the SMSTask class waits for 2 seconds.

Exploring @RestController

JAX-RS provides the functionality for Representational State Transfer (RESTful) web services. REST is well-suited for basic, ad hoc integration scenarios. Spring MVC offers controllers to create RESTful web services.

In Spring MVC 3.0, we need to explicitly annotate a class with the @Controller annotation in order to specify a controller servlet and annotate each and every method with @ResponseBody to serve JSON, XML, or a custom media type. With the advent of the Spring 4.0 @RestController stereotype annotation, we can combine @ResponseBody and @Controller.

The following example will demonstrate the usage of @RestController:

  1. Create a dynamic web project, RESTfulWeb.
  2. Modify the web.xml file and add a configuration to intercept requests with a Spring DispatcherServlet:
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.
    sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://
    java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webapp_
    3_0.xsd" id="WebApp_ID" version="3.0">
    <display-name>RESTfulWeb</display-name>
    <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/dispatcher-servlet.xml
    </param-value>
    </context-param>
    </web-app>
  3. The DispatcherServlet expects a configuration file with the naming convention [servlet-name]-servlet.xml. Create an application context XML, dispatcher-servlet.xml. We'll use annotations to configure Spring beans, so we need to tell the Spring container to scan the Java package in order to craft the beans. Add the following lines to the application context in order to instruct the container to scan the com.packt.controller package:
    <context:component-scan base-package= "com.packt.controller" />
    <mvc:annotation-driven />
  4. We need a REST controller class to handle the requests and generate a JSON output. Go to the com.packt.controller package and add a SpringService controller class. To configure the class as a REST controller, we need to annotate it with the @RestController annotation. The following code snippet represents the class:
    @RestController
    @RequestMapping("/hello")
    public class SpringService {
    private Set<String> names = new HashSet<String>();
    @RequestMapping(value = "/{name}", method =
             RequestMethod.GET)
    public String displayMsg(@PathVariable String name) {
       String result = "Welcome " + name;
       names.add(name);
       return result;
    }
    @RequestMapping(value = "/all/", method =
             RequestMethod.GET)
    public String anotherMsg() {
       StringBuilder result = new StringBuilder("We
             greeted so far ");
       for(String name:names){
         result.append(name).append(", ");
       }
       return result.toString();
     }
    }

    We annotated the class with @RequestMapping("/hello"). This means that the SpringService class will cater for the requests with the http://{site}/{context}/hello URL pattern, or since we are running the app in localhost, the URL can be http://localhost:8080/RESTfulWeb/hello.

    The displayMsg method is annotated with @RequestMapping(value = "/{name}", method = RequestMethod.GET). So, the method will handle all HTTP GET requests with the URL pattern /hello/{name}. The name can be any String, such as /hello/xyz or /hello/john. In turn, the method stores the name to Set for later use and returns a greeting message, welcome {name}.

    The anotherMsg method is annotated with @RequestMapping(value = "/all/", method = RequestMethod.GET), which means that the method accepts all the requests with the http://{SITE}/{Context}/hello/all/ URL pattern. Moreover, this method builds a list of all users who visited the /hello/{names} URL. Remember, the displayMsg method stores the names in Set; this method iterates Set and builds a list of names who visited the /hello/{name} URL.

    There is some confusion though: what will happen if you enter the /hello/all URL in the browser? When we pass only a String literal after /hello/, the displayMsg method handles it, so you will be greeted with welcome all. However, if you type /hello/all/ instead—note that we added a slash after all—it means that the URL does not match the /hello/{name} pattern and the second method will handle the request and show you the list of users who visited the first URL.

  5. When we run the application and access the /hello/{name} URL, the following output is displayed:Mockito for Spring

    When we access http://localhost:8080/RESTfulWeb/hello/all/, the following output is displayed:Mockito for Spring

    Therefore, our RESTful application is ready for use, but just remember that in the real world, you need to secure the URLs against unauthorized access. In a web service, development security plays a key role. You can read the Spring security reference manual for additional information.

Learning AsyncRestTemplate

We live in a small, wonderful world where everybody is interconnected and impatient! We are interconnected through technology and applications, such as social networks, Internet banking, telephones, chats, and so on. Likewise, our applications are interconnected; often, an application housed in India may need to query an external service hosted in Philadelphia to get some significant information.

We are impatient as we expect everything to be done in seconds; we get frustrated when we make an HTTP call to a remote service, and this blocks the processing unless the remote response is back. We cannot finish everything in milliseconds or nanoseconds, but we can process long-running tasks asynchronously or in a separate thread, allowing the user to work on something else.

To handle RESTful web service calls asynchronously, Spring offers two useful classes: AsyncRestTemplate and ListenableFuture. We can make an async call using the template and get Future back and then continue with other processing, and finally we can ask Future to get the result.

This section builds an asynchronous RESTful client to query the RESTful web service we developed in the preceding section. The AsyncRestTemplate class defines an array of overloaded methods to access RESTful web services asynchronously. We'll explore the exchange and execute methods.

The following are the steps to explore the template:

  1. Create a package, com.packt.rest.template.
  2. Add a AsyncRestTemplateTest JUnit test.
  3. Create an exchange() test method and add the following lines:
    @Test
    public void exchange(){
    AsyncRestTemplate asyncRestTemplate = new
    AsyncRestTemplate();
    String url ="http://localhost:8080/RESTfulWeb/
    hello/all/";
    HttpMethod method = HttpMethod.GET;
    Class<String> responseType = String.class;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.TEXT_PLAIN);
    HttpEntity<String> requestEntity = new
    HttpEntity<String>("params", headers);
    ListenableFuture<ResponseEntity<String>> future =
    asyncRestTemplate.exchange(url, method,
    requestEntity, responseType);
    try {
    //waits for the result
    ResponseEntity<String> entity = future.get();
    //prints body of the given URL
    System.out.println(entity.getBody());
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    }

    The exchange() method has six overloaded versions. We used the method that takes a URL, an HttpMethod method such as GET or POST, an HttpEntity method to set the header, and finally a response type class. We called the exchange method, which in turn called the execute method and returned ListenableFuture. The ListenableFuture is the handle to our output; we invoked the GET method on ListenableFuture to get the RESTful service call response. The ResponseEntity has the getBody, getClass, getHeaders, and getStatusCode methods for extracting the web service call response.

    We invoked the http://localhost:8080/RESTfulWeb/hello/all/ URL and got back the following response:Mockito for Spring

  4. Now, create an execute test method and add the following lines:
    @Test public void execute(){
    AsyncRestTemplate asyncTemp = new AsyncRestTemplate();
    String url ="http://localhost:8080/RESTfulWeb
    /hello/reader";
    HttpMethod method = HttpMethod.GET;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.TEXT_PLAIN);
    AsyncRequestCallback requestCallback = new
    AsyncRequestCallback (){
    @Override
    public void doWithRequest(AsyncClientHttpRequest
    request) throws IOException {
    System.out.println(request.getURI());
    }
    };
    ResponseExtractor<String> responseExtractor = new
    ResponseExtractor<String>(){
    @Override
    public String extractData(ClientHttpResponse
    response) throws IOException {
    return response.getStatusText();
    }
    };
    Map<String,String> urlVariable = new HashMap<String,
    String>();
    ListenableFuture<String> future = asyncTemp.execute(url,
    method, requestCallback, responseExtractor,
    urlVariable);
    try {
    //wait for the result
    String result = future.get();
    System.out.println("Status =" +result);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    }

    The execute method has several variants. We invoke the one that takes a URL, HttpMethod such as GET or POST, an AsyncRequestCallback method which is invoked from the execute method just before executing the request asynchronously, a ResponseExtractor to extract the response, such as a response body, status code or headers, and a URL variable such as a URL that takes parameters. We invoked the execute method and received a future, as our ResponseExtractor extracts the status code. So, when we ask the future to get the result, it returns the response status which is OK or 200. In the AsyncRequestCallback method, we invoked the request URI; hence, the output first displays the request URI and then prints the response status.

    The following is the output:Mockito for Spring

Caching objects

Scalability is a major concern in web application development. Generally, most web traffic is focused on some special set of information. So, only those records are queried very often. If we can cache these records, then the performance and scalability of the system will increase immensely.

The Spring Framework provides support for adding caching into an existing Spring application. In this section, we'll work with EhCache, the most widely used caching solution. Download the latest EhCache JAR from the Maven repository; the URL to download version 2.7.2 is http://mvnrepository.com/artifact/net.sf.ehcache/ehcache/2.7.2.

Spring provides two annotations for caching: @Cacheable and @CacheEvict. These annotations allow methods to trigger cache population or cache eviction, respectively.

The @Cacheable annotation is used to identify a cacheable method, which means that for an annotate method the result is stored into the cache. Therefore, on subsequent invocations (with the same arguments), the value in the cache is returned without actually executing the method.

The cache abstraction allows the eviction of cache for removing stale or unused data from the cache. The @CacheEvict annotation demarcates the methods that perform cache eviction, that is, methods that act as triggers to remove data from the cache.

The following are the steps to build a cacheable application with EhCache:

  1. Create a serializable Employee POJO class in the com.packt.cache package to store the employee ID and name. The following is the class definition:
    public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private final String firstName, lastName, empId;
     
    public Employee(String empId, String fName, String lName) {
       this.firstName = fName;
       this.lastName = lName;
       this.empId = empId;
    //Getter methods
  2. Spring caching supports two storages: the ConcurrentMap and ehcache libraries. To configure caching, we need to configure a manager in the application context. The org.springframework.cache.ehcache.EhCacheCacheManager class manages ehcache. Then, we need to define a cache with a configurationLocation attribute. The configurationLocation attribute defines the configuration resource. The ehcache-specific configuration is read from the resource ehcache.xml.
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-
    4.1.xsd
    http://www.springframework.org/schema/cache http://www.
    springframework.org/schema/cache/spring-cache-
    4.1.xsd
    http://www.springframework.org/schema/context http://www.
    springframework.org/schema/context/springcontext-
    4.1.xsd ">
    <context:component-scan base-package=
    "com.packt.cache" />
    <cache:annotation-driven/>
    <bean id="cacheManager" class="org.springframework.cache.
    ehcache.EhCacheCacheManager"
    p:cacheManager-ref="ehcache"/>
    <bean id="ehcache" class="org.springframework.cache.
    ehcache.EhCacheManagerFactoryBean"
    p:configLocation="classpath:com/packt/cache/ehcache.xml"/>
    </beans>

    The <cache:annotation-driven/> tag informs the Spring container that the caching and eviction is performed in annotated methods. We defined a cacheManager bean and then defined an ehcache bean. The ehcache bean's configLocation points to an ehcache.xml file. We'll create the file next.

  3. Create an XML file, ehcache.xml, under the com.packt.cache package and add the following cache configuration data:
    <ehcache>
       <diskStore path="java.io.tmpdir"/>
       <cache name="employee"
               maxElementsInMemory="100"
               eternal="false"
               timeToIdleSeconds="120"
               timeToLiveSeconds="120"
               overflowToDisk="true"
               maxElementsOnDisk="10000000"
               diskPersistent="false"
               diskExpiryThreadIntervalSeconds="120"
               memoryStoreEvictionPolicy="LRU"/>
     
    </ehcache>

    The XML configures many things. Cache is stored in memory, but memory has a limit, so we need to define maxElementsInMemory. EhCache needs to store data to disk when max elements in memory reaches the threshold limit. We provide diskStore for this purpose. The eviction policy is set as an LRU, but the most important thing is the cache name. The name employee will be used to access the cache configuration.

  4. Now, create a service to store the Employee objects in a HashMap. The following is the service:
    @Service
    public class EmployeeService {
    private final Map<String, Employee> employees = new
    ConcurrentHashMap<String, Employee>();
    @PostConstruct
    public void init() {
    saveEmployee (new Employee("101", "John", "Doe"));
    saveEmployee (new Employee("102", "Jack",
    "Russell"));
    }
    @Cacheable("employee")
    public Employee getEmployee(final String employeeId) {
    System.out.println(String.format("Loading a
    employee with id of : %s", employeeId));
    return employees.get(employeeId);
    }
    @CacheEvict(value = "employee", key = "#emp.empId")
    public void saveEmployee(final Employee emp) {
    System.out.println(String.format("Saving a emp with
    id of : %s", emp.getEmpId()));
    employees.put(emp.getEmpId(), emp);
    }
    }

    The getEmployee method is a cacheable method; it uses the cache employee. When the getEmployee method is invoked more than once with the same employee ID, the object is returned from the cache instead of the original method being invoked. The saveEmployee method is a CacheEvict method.

  5. Now, we'll examine caching. We'll call the getEmployee method twice; the first call will populate the cache and the subsequent call will be responded toby the cache. Create a JUnit test, CacheConfiguration, and add the following lines:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:com/packt/cache/
    applicationContext.xml")
    public class CacheConfiguration {
    @Autowired
    ApplicationContext context;
    @Test public void jobTest() throws Exception {
    EmployeeService employeeService =
    (EmployeeService)context.getBean(EmployeeService.class);
    long time = System.currentTimeMillis();
    employeeService.getEmployee("101");
    System.out.println("time taken
    ="+(System.currentTimeMillis() - time));
    time = System.currentTimeMillis();
    employeeService.getEmployee("101");
    System.out.println("time taken to read from cache
    ="+(System.currentTimeMillis() - time));
    time = System.currentTimeMillis();
    employeeService.getEmployee("102");
    System.out.println("time taken
    ="+(System.currentTimeMillis() - time));
    time = System.currentTimeMillis();
    employeeService.getEmployee("102");
    System.out.println("time taken to read from cache
    ="+(System.currentTimeMillis() - time));
    employeeService.saveEmployee(new Employee("1000",
    "Sujoy", "Acharya"));
    time = System.currentTimeMillis();
    employeeService.getEmployee("1000");
    System.out.println("time taken
    ="+(System.currentTimeMillis() - time));
    time = System.currentTimeMillis();
    employeeService.getEmployee("1000");
    System.out.println("time taken to read from cache
    ="+(System.currentTimeMillis() - time));
    }
    }

    Note that the getEmployee method is invoked twice for each employee, and we recorded the method execution time in milliseconds. You will find from the output that every second call is answered by the cache, as the first call prints Loading a employee with id of : 101 and then the next call doesn't print the message but prints the time taken to execute. You will also find that the time taken for the cached objects is zero or less than the method invocation time.

    The following screenshot shows the output:Mockito for Spring

Summary

This article started with discovering the features of the new major Spring release 4.0, such as Java 8 support and so on. Then, we picked four Spring 4 topics and explored them one by one.

The @Async section showcased the execution of long-running methods asynchronously and provided an example of how to handle asynchronous processing.

The @RestController section eased the RESTful web service development with the advent of the @RestController annotation.

The AsyncRestTemplate section explained the RESTful client code to invoke RESTful web service asynchronously.

Caching is inevitable for a high-performance, scalable web application. The caching section explained the EhCache and Spring integrations to achieve a high-availability caching solution.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Mockito for Spring

Explore Title