Engineering
Costin Leau
February 23, 2011
One of the major features added in Spring Framework 3.1 M1 is the generic cache abstraction for transparently applying caching to Spring applications. Just like the transaction support, the caching abstraction allows consistent use of various caching solutions with minimal impact on the code.
Purpose
Caches are in general used to improve application performance by transparently serving frequently accessed data in a faster fashion such as serving data from local memory rather than from the network. Many of you have already used caching, whether knowingly or not: most ORM/JPA frameworks provide dedicated caching functionality (also known as the 2nd-level cache). Spring 3.1 M1 however introduces a generic cache mechanism that can be applied to any Java class, method or library: one can use it in conjunction with an existing caching infrastructure, to add caching to APIs without such support (for example JDBC) or simply to improve the performance of a slow, time-consuming and resource-hungry method.
Meet @Cacheable, @CacheEvict and SpEL
Let us see what it takes to cache an arbitrary method:
@Cacheable(“books”)
public Book findBook(ISBN isbn) {…}
By marking the method with the @Cacheable annotation, we tell the container that the findBook method is backed by the cache entry books. That is each time the method is called, a cache lookup is performed using as key the method parameters (in this case the isbn argument). If a value is found, it will be returned and the method execution skipped. However, if the key is not found, the method is executed as usual and its result stored in the cache so the next time the method is invoked, the result can be returned without actually executing the (expensive or slow) method.
In practice not all methods have only one argument or, worse yet, the parameters are not suitable as cache keys - take for example a variation of the method above:
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
In such cases, one can use Spring 3 Spring Expression Language or SpEL to cherry pick the proper arguments, navigate the object tree
// use property ‘rawNumber’ on isbn argument as key
@Cacheable(value=“book”, key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
or compute the key on the fly, even call arbitrary methods without having to write any code:
// get the key by calling someType#hash(isbn)
@Cacheable(value=“book”, key=“T(someType).hash(#isbn)”)
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
Additionally, one can specify when or if the caching should occur: whether the cache should be inspected or completely disregarded and the method executed normally. It’s up to the developer to decide what the criteria is: can be anything from the key size or type to the time of day or result of arbitrary methods: SpEL supports it all:
// cache only names shorter then 32 chars
@Cacheable(value=“book”, condition="#name.length < 32")
public Book findBook(String name)
// do not cache on weekends
@Cacheable(value=“book”, condition="!T(TimeUtils).isWeekend()")
public Book findBook(String name)
The cache abstraction also supports eviction of cache entries or of an entire cache through the @CacheEvict annotation. To evict a cache once it becomes invalid (for example because the cached data has been updated) one can use the following:
// evict all cache entries
@CacheEvict(value = “books”, allEntries=true)
public void loadBooks(InputStream batch)
Once the annotations are in place, one can simply “enable” the caching functionality with one line (or three if you count the schema declaration):
<cache:annotation-driven />
…
Just like the rest of the annotation-driven element, the cache one uses defaults in its simplest form but can be used to pick between proxy and byte-code weaving of cached classes or to wire in the desired cache implementation.
Declaring a cache implementation
So far, we discussed the declarative aspect of the caching abstraction: how to add and remove data from the cache based on your POJOs. But what are the backing cache implementations that one can use?
Out of the box, Spring provides integration with ehcache and JDK ConcurrentHashMap great for small, non-distributed environments or testing:
What about [xx] library - when will it be supported ?
For the moment we do not plan to support other caching libraries inside Spring Framework simply because of the sheer number of options out there, the dependency impact (many are bigger in size than the cache abstraction), and the maintenance and licensing issues. To plug-in a custom cache provider, we encourage developers to look at the caching SPI package and its two interfaces: CacheManager and Cache. Besides the implementations available out of the box, one can look at the GemFire implementation, scheduled for the next major release version of Spring GemFire.
How does the caching abstraction compare to other caches (e.g. JPA 2nd-level cache) ?
In general, the two caching mechanisms can happily coexist as long as the developer pays attention to any domain overlap. Taking the example of the JPA 2nd-level cache, one can used it for data access through JPA while using Spring caching for the web-tier or remote service calls. One can go a step further by reusing the backed cache between the two mechanisms if that applies.
Summary
I hope you enjoyed this quick introductory entry to the new caching feature in Spring 3.1. For more information, please see the relevant reference documentation chapter and the SPI javadoc. And do let us know what you think - we are interested in your feedback! You can reach us through the forum, blog post comments, our issue tracker or yours truly on Twitter.
comments powered by Disqus
translate:
翻译:
Spring Framework 3.1m1中添加的主要特性之一是通用缓存抽象,用于透明地将缓存应用于Spring应用程序。与事务支持一样,缓存抽象允许一致地使用各种缓存解决方案,对代码的影响最小。
目的
缓存通常用于提高应用程序性能,方法是以更快的方式透明地为频繁访问的数据提供服务,例如从本地内存而不是从网络提供数据。很多人已经使用过缓存,不管是有意还是无意:大多数ORM/JPA框架提供专用的缓存功能(也称为二级缓存)。然而,Spring 3.1m1引入了一种可应用于任何Java类、方法或库的通用缓存机制:可以将其与现有的缓存基础设施结合使用,在没有这种支持的情况下(例如JDBC)将缓存添加到api中,或者仅仅是为了提高一个缓慢、耗时且资源匮乏的方法的性能。
遇到@Cacheable,@CacheEvict和SpEL