Simple Spring Memcached – Spring Caching Abstraction and Memcached

Caching remains the one of the most basic performance enhancing mechanism in any read heavy database application. Spring 3.1 release came up with a cool new feature called Cache Abstraction. Spring Cache Abstraction provides the application developers an easy, transparent and decoupled way to implement any caching solution. Memcached is one of the most popular distributed caching system used across apps. In this post we will focus on how to integrate memcached with a Spring enabled applications. Since Spring directly supports only Ehcache and ConcurrentHashMap so we will fall down to a third party library Simple Spring Memcache to leverage power of spring caching abstraction.
 
 

Getting The Code

Code for this tutorial can be downloaded from following SVN location. https://www.assembla.com/code/weblog4j/subversion/nodes/24/SpringDemos/trunk For the tutorial to work please create the following table in your db. Then modify the datasource in springcache.xml.

CREATE  TABLE IF NOT EXISTS `adconnect`.`books` (
  `book_id` INT NOT NULL AUTO_INCREMENT ,
  `book_name` VARCHAR(500) NULL ,
  `book_author` VARCHAR(500) NULL ,
  `category` VARCHAR(500) NULL ,
  `numpages` INT NULL ,
  `price` FLOAT NULL ,
  PRIMARY KEY (`book_id`) )
ENGINE = InnoDB;

Integration Steps

1. Dependencies - I also assume that you have your hibernate, spring and logs set up. So for downloading SSM dependencies add following to your POM. For full set of dependencies please download the project from SVN url above.

<dependency>
     <groupId>com.google.code.simple-spring-memcached</groupId>
     <artifactId>spring-cache</artifactId>
     <version>3.1.0</version>
</dependency>

<dependency>
     <groupId>com.google.code.simple-spring-memcached</groupId>
     <artifactId>xmemcached-provider</artifactId>
     <version>3.1.0</version>
</dependency>

2. Enable Caching – To enable caching in your spring application add following to your spring context xml.

<cache:annotation-driven/>

3. Configure Spring to enable Memcached based caching  – Add following to your application context xml.

<bean name="cacheManager" class="com.google.code.ssm.spring.SSMCacheManager">
     <property name="caches">
         <set>
             <bean class="com.google.code.ssm.spring.SSMCache">
                 <constructor-arg name="cache" index="0" ref="defaultCache"/>
                 <!-- 5 minutes -->
                 <constructor-arg name="expiration" index="1" value="300"/>
                 <!-- @CacheEvict(..., "allEntries" = true) doesn't work -->
                 <constructor-arg name="allowClear" index="2" value="false"/>
             </bean>
         </set>
     </property>

    </bean>

<bean name="defaultCache" class="com.google.code.ssm.CacheFactory">
     <property name="cacheName" value="defaultCache"/>
     <property name="cacheClientFactory">
        <bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl"/>
     </property>
     <property name="addressProvider">
         <bean class="com.google.code.ssm.config.DefaultAddressProvider">
            <property name="address" value="127.0.0.1:11211"/>
         </bean>
     </property>
     <property name="configuration">
         <bean class="com.google.code.ssm.providers.CacheConfiguration">
             <property name="consistentHashing" value="true"/>
         </bean>
     </property>

</bean>

SSMCacheManager extends org.springframework.cache.support.AbstractCacheManager – It is an  abstract class and is a manager for underlying Cache.

SSMCache implements org.springframework.cache.Cache – This is actual  wrapper round underlying cache client api.

4. Annotation Driven caching – Spring uses annotation to mark a method that it is to be managed by  cache.  These are the annotations defined by spring caching framework

  1. @Cacheable – This annotation is used to mark a method whose results are to be cached. If a cacheable method is called then spring first looks if result of the method is cached or not. If it present in cache then result is pulled from there else it the method call is made.                                                                                                                         
  2. @CachePut – Methods marked with cacheput annotations are always run and their results are pushed to cache. You should not place both Cacheput and Cacheable annotation on same method as they have different behaviour. Cacheput will result in method getting executed all the time while cacheable results in method getting executed only once.
  3. @CacheEvict – This annotation results in eviction of objects from the cache. This is generally used when the result object is updated hence the old object from cache needs to be purged.
  4. @Caching – This annotation is used if multiple annotations of same type is to be put on a method.

@Cacheable Demo 

@Cacheable(value = "defaultCache", key = "new Integer(#book_id).toString().concat('.BookVO')")
    public BookVO get(int book_id) throws Exception {
        BookVO bookVO = null;
		try{
			Query query = getSession().createQuery("from BookVO bookVO where bookVO.book_id=:book_id");
			query.setLong("book_id", book_id);
			bookVO =  (BookVO)query.uniqueResult();
		}catch(HibernateException he){
			log.error("Error in finding a bookVO : " + he);
            throw new Exception("Error in finding adPicVO by book_id for book_id : " + bookVO, he);
		}
		return bookVO;
    }

Please note the key attribute of the annotation. This is an example of Spring Expression Language. You can use SePL use to create memcache key according to your requirement. In this example I want a key which should be of form <book_id>.BookVO. 

Another Example – Lets say I want to store a list of bookVO from a given author in that case I can a unique key of form <author_name>.BookVOList so for that I can use following key

@Cacheable(value = "defaultCache", key = "#author.concat('.BookVOList')")
    public List<BookVO> getList(String author) throws Exception {

@CachePut Demo

@CachePut(value = "defaultCache", key = "new Integer(#bookVO.book_id).toString().concat('.BookVO')")
    public BookVO create(BookVO bookVO) throws Exception {
        try{
			getSession().save(bookVO);
			getSession().flush();
		}catch(HibernateException he){
			log.error("Error in inserting bookVO : " + he);
            throw new Exception("Error in inserting bookVO", he);
		}

		return bookVO;
    }

CachePut can be used while inserting data where data inserted can be put in cache after insertion is done

@CacheEvict Demo

@CacheEvict(value = "defaultCache", key = "new Integer(#bookVO.book_id).toString().concat('.BookVO')")
    public BookVO update(BookVO bookVO) throws Exception {
        try{
            Query query = getSession().createQuery("update BookVO bookVO set bookVO.book_name=:book_name, bookVO.book_author=:book_author,bookVO.category=:category,bookVO.numpages=:numpages,bookVO.price=:price " +
                                                   "where bookVO.book_id=:book_id");
            query.setString("book_name", bookVO.getBook_name());
            query.setString("book_author", bookVO.getBook_author());
            query.setString("category", bookVO.getCategory());
            query.setInteger("numpages", bookVO.getNumpages());
            query.setFloat("price", bookVO.getPrice());
			query.setLong("book_id", bookVO.getBook_id());
            query.executeUpdate();
		}catch(HibernateException he){
			log.error("Error in updating bookVO : " + he);
            throw new Exception("Error in updating bookVO", he);
		}

		return bookVO;
    }

Resources

  1. https://code.google.com/p/simple-spring-memcached/
  2. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/cache.html
  3. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/expressions.html
  4. http://static.springsource.org/spring/docs/3.1.0.M1/javadoc-api/index.html?org/springframework/cache/CacheManager.html
  5. http://doanduyhai.wordpress.com/2012/07/01/cache-abstraction-in-spring-3/
  6. http://viralpatel.net/blogs/cache-support-spring-3-1-m1/

 

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


4 + = seven



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books