| 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. |
| |
| h4. 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. |
| |
| h4. 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). |
| |
| h5. 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@. |
| |
| h4. 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: |
| |
| {code} |
| <cache:block> |
| foo |
| </cache:block> |
| |
| <cache:block> |
| bar |
| </cache:block> |
| {code} |
| |
| 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. |
| |
| h4. Service caching |
| |
| You can cache the return value of a service method by annotating it with @Cacheable@. |
| |
| h5. 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: |
| |
| {code} |
| 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; |
| } |
| {code} |
| |
| 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. |
| |
| h4. 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@. |
| |
| h4. 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@. |