Thursday, September 20, 2012

Proxy vs AspectJ Caching with Spring

All my previous caching examples used Proxy caching.  
<cache:annotation-driven/> has a 'mode' attribute which by default is set to 'proxy'. Spring will proxy your annotated beans using Spring's AOP framework. This means that cross cutting will be applied to method calls coming in through the proxy. How can that potentially be a problem?

Let's take a simple example of calling a service to retrieve a Book.
  
Book has a references to an Author object
We will cache Book and Author objects separately (to avoid duplication) and when the service returns an instance of the Book, Author will be set. We annotated getBookWithNoAuthor and getAuthor methods, which means the result of those methods will be cached by ISBN number.

When calling libraryService.getBook(isbn), I noticed that caching is not used, however when calling libraryService.getBookWithNoAuthor(isbn), caching is triggered.

Explanation: Spring created a Proxy libraryService class and all caching invocation is done inside the proxy. Once the proxy calls your libraryService, any other method invocations (this.getBookWithNoAuthore, this.getAuthor) from within the class are not routing through the proxy.

Solution: Other than merging all 3 methods and potentially caching duplicate data, our other solution is to use AspectJ weaving.

You can read more on AspectJ and how it works, but in summary it will modify the target class byte code to include caching for each method, there is no proxy creation.

AspectJ Setup: 
  1. In your Spring context file, add mode="aspectj"  
    <cache:annotation-driven mode="aspectj"/>
  2. In your Spring context file, add <context:load-time-weaver/>
  3. Add dependencies to your pom file:

For JUnit testing make sure you add a JVM variable:
     -javaagent:\spring-instrument.jar

For Tomcat you need to specify class loader explicitly.

  1.  Copy org.springframework.instrument.tomcat.jar to $CATALINA_HOME/lib. 
  2.  Update server.xml to instruct Tomcat to use a custom class loader: 
That's it! If you can get away with using default mode (proxy) then stick with that.

Tuesday, April 10, 2012

Spring Cache + Couchbase NoSQL DB

This post expands on the previous Library example using Couchbase as NoSQL database. You can download and configure Couchbase server from their site. Spring Cache is only a cache abstraction so we must implement the backing cache (where the data is stored to and read from), in this case Couchbase.
  1. Implement Cache Manager.  Our cache manager will extend AbstractCacheManager from Spring, which takes care of the boiler-plate code. We will implement only loadCaches method which will be used to preload all caches. When you configure Couchbase using the admin console, one of your configurations is setting up Data Buckets; these buckets will be your caches.

    • We store an array list of cacheNames (data bucket names). This list will be injected by Spring from spring-context file.
    • loadCaches method creates an instance of each Cache. My Couchbase server is configured with 2 buckets, 'default' and 'books' so I will configure 2 Caches (one for each bucket). Default cache will load objects into 'default' data bucket and Books cache will load objects into 'books' bucket. Note: Unlike some other cache servers, Couchbase will not create a new bucket programmatically. All buckets must be configured on the server before your code can use them.
  2. Implement Cache. Our cache class will extend Cache from Spring. Here we connect to the Couchbase server, implement put, get, evict and clear methods.

    • init() establishes a connection to Couchbase server for a specific Bucket name. That bucket name must match your Couchbase configuration.
    • get and put methods are straightforward. Note: Couchbase accepts String objects as keys not allowing spaces.
    • We wrap our cached object in ValueWrapper
  3. Adding Caching with Annotations. Since Couchbase does not like spaces in its keys, for this example we will cache by ISBN (key="#isbn"). Cache (bucket) name is 'books'  (value="books").
  4. Configuring Application Context. Now we will modify our Spring application context file to configure the custom CacheManager and Cache.
    • Use cacheManager as the bean name, that's what Spring Cache looks for. While initializing CacheManager we are passing 2 bucket names configured on Couchbase server.
  5. Maven dependencies.

This is pretty much all you need to plug in Spring Cache with Couchbase.

When you run your JUnit tests you will notice that when you call LibraryService.getBook method the first time, Spring creates a proxy class of your Library Service and will call getBook method on the proxy class. Proxy will call get() to check if the object has been cached. Since this is your first call, the object returned is null and the proxy class will invoke your LibraryService.getBook method. The returned value will then be placed into cache with put(). Second call to the same method (with same parameters) will return the object from cache.

Tuesday, March 6, 2012

Spring Cache - Using SimpleCacheManager

We will create a simple application that uses Spring Cache Abstraction using JDK ConcurrentMap based cache. This will allow ConcurrentHashMap to be used as a backing Cache storage.

Overview of our Library:
POJOs - Book.java, Author.java
Service - LibraryService.java
Implementation of Library - Library interface, HomeLibraryImpl.java

Before we plug in Spring, we will create the classes mentioned above. Then we will use Spring to Autowire and Cache.
  1. Create a Maven project. Here is a pom file with all the jar dependencies needed for this application.

  2. Create simple POJOs. We have a Book which has a Title, Author and ISBN.


  3. LibraryService is our service class that exposes our Library operations. We will add Spring specific annotations later on to this class.

  4. We have a Library interface that has 3 methods, getBook(String title, Author author), getBook(long isbn) and addBook(Book book).

  5. We will create 1 implemention class for our Library. Since we are not hitting a database, all the books will be preloaded in a HashMap. We will call our implementation class HomeLibraryImpl. To make this example simple we will have 2 maps with different keys storing our books to make our search easier.

  6. Adding Spring Autowiring into our classes. We need to inject the HomeLibraryImpl into our LibraryService to be used as implementing class. Add @Autowired annotation in LibraryService to our Library property.

  7. Create spring application context file.

  • Line 16 : Used to activate annotations in beans that are registered in the application context, Lines 19 and 21. Spring scans for @Autowired annotation and the bean name defined in application context matches property name in LibraryService.
  • Line 17 : Informs Spring that it should process the cache annotations (i.e. @Cacheable)
  • Line 24 : We declare cacheManager bean for Spring cache and use SimpleCacheManager
  • Line 27, 28 : Nested beans to declare Concurrent Cache implementations


  • Adding Spring Cache annotations to your Service class. @Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method.

    Value "books" matches our nested bean in application context (Line 21). This means that the result of this method will be cached under "books" concurrent map. I added key to show you how we can concatenate method parameters to create a key. Spring uses SpEL for key expressions.
  • Testing your application with JUnit

    If you put a break point or a log statement inside getBook method in HomeLibraryImpl class, you will notice that on the second call to retrieve the book the method is not invoked and the Book object returned is from Cache and not from our HashMap.
  • Thursday, March 1, 2012

    Spring - Multiple Application Context files from Different Projects

    • Web Application needs to use application context files bundled in separate projects.
      1. Insert the following into web.xml file



        classpath* - searches for files in the classpath.


        Project A - contains projectA-context.xml


        Project B - contains projectB-context.xml


        Project C - contains application-context.xml


        Project D - contains application-context.xml


        All 4 context files will be loaded in that order if all 4 projects are in the classpath

    • JUnit testing with multiple application context files bundled in separate projects.
      1. Add all dependent projects to the classpath when executing JUnit
      2. Include other resources in your main application context

        Project A - executed with JUnit, Spring container initiallized with projectA-context.xml

        Project B - contains projectB-context.xml

        Project C - contains application-context.xml

        Project D - contains application-context.xml

        All 4 context files will be loaded in that order if all 4 projects are in the classpath
      3. Spring application context injecting into JUnit

    Thursday, February 2, 2012

    Simple Examples using Kryo for Serialization

    Kryo is a fast and efficient way of Serialization in Java. Below are a couple of simple examples using Kryo.

    Note: Since I am using a ByteBuffer to write and read, you must call flip() on the buffer before you de-serialize. The buffer keeps current position of the last byte, that position is used to write/read into the buffer. If you read without flip() the position will be current (until buffer limit). By calling flip(), you are resetting current position to the beginning of the buffer. Good explanation in the following blog.
    1. 2 Ways to do a simple String serialization/deserialization




    2. List Serialization

    3. Custom bean Serialization


    Saturday, January 14, 2012

    Adding Spring MVC to Spring Web Services Part 2

    In this example we will create a Person request handled by Spring MVC framework. Towards the end, I will summarize how both Spring MVC and Spring Web Services can be in the same application but used differently.
    1. Create an entry point into your Web Application. We will create a simple HTML file

    2. Create welcome-file in your web.xml

    3. Now lets add Spring to our application. In web.xml add a front controller mapping for Spring. This controller will control where all requests are routed based on configuration we will set up later.

      • Line 2 - Servlet name will be used for our Spring configuration files
      • Line 3 - DispatcherServlet used as a front controller
      • Line 8 - Any URL that ends with .htm will be served by DispatcherServlet
    4. Create configuration file used by DispatcherServlet containing definitions for all beans. The name of the file is derived from using servlet-name defined in web.xml and appending "-servlet".

      Here we have defined a bean (/person.htm) with a mapping to a Page Controller, which is responsible for handling a request for a particular page of the website. HandlerMapping is an interface that maps between a request URL and the object that is going to handle that request (the handler). The default handler for DispatcherServlet is BeanNameUrlHandlerMapping which uses the bean name defined in this config file to map to the URL in the request so that the DispatcherServlet knows which controller must be invoked for handling different URLs.
    5. Create PersonController

      Since we have not explicitly defined a ViewResolver, we are going to be given a default one by Spring that simply forwards to a URL matching the name of the view specified.
    6. Create Person view, this is the view that is returned by the PersonController. Because we are using a default ViewResolver, place this file in your WebContent folder (outside of WEB-INF)

    7. List of JARs
      • commons-logging
      • spring.web.servlet
      • spring.web-3.1.0
    8. Test Controller

    9. Deploy your application on a Server. Hit the URL: http://localhost:8080/MyWebServices/person.htm