My objective here is to cover one of the newer cache implementations that Spring now provides with 4.0+ version of the framework - using Google Guava Cache
In brief, consider a service which has a few slow methods:
public class DummyBookService implements BookService {
@Override
public Book loadBook(String isbn) {
// Slow method 1.
}
@Override
public List<Book> loadBookByAuthor(String author) {
// Slow method 2
}
}
With Spring Caching abstraction, repeated calls with the same parameter can be sped up by an annotation on the method along these lines - here the result of loadBook is being cached in to a "book" cache and listing of books cached into another "books" cache:
public class DummyBookService implements BookService {
@Override
@Cacheable("book")
public Book loadBook(String isbn) {
// slow response time..
}
@Override
@Cacheable("books")
public List<Book> loadBookByAuthor(String author) {
// Slow listing
}
}
Now, Caching abstraction support requires a CacheManager to be available which is responsible for managing the underlying caches to store the cached results, with the new Guava Cache support the CacheManager is along these lines:
@Bean
public CacheManager cacheManager() {
return new GuavaCacheManager("books", "book");
}
Google Guava Cache provides a rich API to be able to pre-load the cache, set eviction duration based on last access or created time, set the size of the cache etc, if the cache is to be customized then a guava CacheBuilder can be passed to the CacheManager for this customization:
@Bean
public CacheManager cacheManager() {
GuavaCacheManager guavaCacheManager = new GuavaCacheManager();
guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterAccess(30, TimeUnit.MINUTES));
return guavaCacheManager;
}
This works well if all the caches have a similar configuration, what if the caches need to be configured differently - for eg. in the sample above, I may want the "book" cache to never expire but the "books" cache to have an expiration of 30 mins, then the GuavaCacheManager abstraction does not work well, instead a better solution is actually to use a SimpleCacheManager which provides a more direct way to get to the cache and can be configured this way:
@Bean
public CacheManager cacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
GuavaCache cache1 = new GuavaCache("book", CacheBuilder.newBuilder().build());
GuavaCache cache2 = new GuavaCache("books", CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.MINUTES)
.build());
simpleCacheManager.setCaches(Arrays.asList(cache1, cache2));
return simpleCacheManager;
}
This approach works very nicely, if required certain caches can be configured to be backed by a different caching engines itself, say a simple hashmap, some by Guava or EhCache some by distributed caches like Gemfire.
