(Quick Reference)

5 Implementation Details - Reference Documentation

Authors:

Version: 3.0.0

5 Implementation Details

All of the plugin's classes are designed for extensibility; the classes are all public, and fields and methods are mostly public or protected. Consider subclassing existing classes to reuse as much as possible instead of completely rewriting them.

Cache manager

The core cache plugin registers a grailsCacheManager Spring bean, and the extension plugins replace this bean with one that creates and manages caches for that implementation. The default implementation is an instance of grails.plugin.cache.GrailsConcurrentMapCacheManager which uses grails.plugin.cache.GrailsConcurrentMapCache as its cache implementation. It uses a java.util.concurrent.ConcurrentHashMap to store cached values.

You can customize the cache manager by replacing the grailsCacheManager Spring bean in resources.groovy with your own; either subclass GrailsConcurrentMapCacheManager (e.g. to override the createConcurrentMapCache() method) or by implementing the grails.plugin.cache.GrailsCacheManager interface.

Controller caching

The controller caching is implemented with a filter registered as grailsCacheFilter in web.xml and it is backed by the Spring bean of the same name. The implementation class is grails.plugin.cache.web.filter.simple.MemoryPageFragmentCachingFilter.

The content that is cached is the response generated by GSP (or directly by the controller if a response is rendered programmatically) before Sitemesh applies its template(s).

Key generation

Controller caching uses a key generator, a class that implements the grails.plugin.cache.web.filter.WebKeyGenerator interface (by default a grails.plugin.cache.web.filter.DefaultWebKeyGenerator). This is registered as the webCacheKeyGenerator Spring bean, so customizing the key generation is simply a matter of subclassing DefaultWebKeyGenerator or re-implementing the interface and registering your own webCacheKeyGenerator bean in resources.groovy.

Fragment caching

You can cache partial GSP page sections with the <cache:block> tag. You can specify a key when using this tag but it's in general unnecessary. This is because the block will be rendered with its own Closure, and the default key is the full closure class name. This is unique since the closures aren't re-used; for example these two blocks will be cached independently, even in the same GSP:

<cache:block>
foo
</cache:block>

<cache:block> bar </cache:block>

You can cache the content of templates with the <cache:render> tag. You can specify a key when using this tag but like the block tag, it's in general unnecessary because the default key is the full template class name.

Service caching

You can cache the return value of a service method by annotating it with Cacheable.

Key generation

The default implementation of the org.springframework.cache.interceptor.KeyGenerator used to generate keys for service method calls is org.springframework.cache.interceptor.DefaultKeyGenerator. This is only used if there is no key attribute specified in the annotation for the method. It generates a numeric key, with the following logic:

public Object generate(Object target, Method method, Object… params) {
   if (params.length == 1) {
      return (params[0] == null ? 53 : params[0]);
   }

if (params.length == 0) { return 0; }

int hashCode = 17; for (Object object : params) { hashCode = 31 * hashCode + (object == null ? 53 : object.hashCode()); } return hashCode; }

This is very generic and somewhat risky, since two no-arg methods that use the same cache will store values under the same key (0), and different methods with similar signatures can easily generate the same key for different return values. So it's best to either specify the key attribute in the annotation, or use separate caches.

DSL parsing

The cache plugin's DSL is very basic; only the cache name can be specified. But you could extend it (for example if you customized the cache or cache manager implementation, although a new plugin would probably make more sense) by replacing the grailsCacheConfigLoader Spring bean in resources.groovy. The default implementation is a grails.plugin.cache.ConfigLoader.

Annotation SpEL expression evaluator

You can extend or customize what is SpEL expressions are supported by re-defining the webExpressionEvaluator Spring bean in resources.groovy. The default implementation is an instance of grails.plugin.cache.web.filter.ExpressionEvaluator.