Table of Contents

1. Introduction
1.1. Known Issues
1.2. Release Notes
2. The Cacheable and CacheFlush Annotations
3. Caching Service Methods
3.1. Service Method Cache Keys
3.2 Calling Cached Methods Internally
4. Content Caching
4.1. Caching and Flushing with Controller Actions
4.2. Content Caching and SiteMesh
4.3. Using Annotations at Class Level
4.4. Cache Headers
4.5. Content Cache Keys
4.6. Content Negotiation
4.7. Full Page Caching
4.8. TagLib Caching
5. Cache Selection
6. Programmatic Caching and Flushing
7. Cache Configuration
8.1. Tips
8.2. FAQ
8.3. Upgrading From Earlier Versions

1. Introduction

The Springcache plugin allows you to easily add the following functionality to your Grails project:

The plugin depends on the EhCache and EhCache-Web libraries.

Contact

The plugin code is hosted on GitHub. Please feel free to fork the plugin and contribute patches.

Please raise defects or enhancements against the Grails Springcache plugin component on the Codehaus JIRA.

Questions, comments? mailto:robenergizedwork.com or better still contact me via the Grails User mailing list.

1.1. Known Issues

1.2. Release Notes

1.3

1.2.1

1.2

1.1.3

1.1.2

1.1.1

1.1

1.0.1

1.0

0.2

0.1

2. The Cacheable and CacheFlush Annotations

The Springcache plugin provides two annotations that are the basis of how you can apply caching and flushing behaviour to both Spring bean methods and page fragments. Both annotations are in the grails.plugin.springcache.annotations package.

The @Cachable annotation

The Cacheable annotation is applied to methods on Spring managed beans such as Grails services to cache method results or to controller actions to cache page fragments. The annotation requires a cache name specified either as a standalone value or with the cache element. The following declarations are equivalent:

@Cacheable("myCache")
@Cacheable(cache = "myCache")

To resolve the cache name in a non-standard way you can supply a cacheResolver element, see Cache Selection. For content caching only you can also supply a keyGenerator element, see Content Cache Keys

The @CacheFlush annotation

The CacheFlush annotation can be applied in the same places as the Cacheable annotation but instead of caching results it will cause a cache or set of caches to be flushed. The CacheFlush annotation requires a single element or a String array either as a standalone value or with the caches element. Either way the elements can simply be literal cache names or regular expression patterns that may match multiple cache names. For example:

@CacheFlush("myCache")
@CacheFlush(/w+ControllerCache/)
@CacheFlush(["cacheA", "cacheB", "cacheC"])
@CacheFlush(caches = ["cacheA", "cacheB", "cacheC"])
@CacheFlush([/cache[A-Z]/, "myCache"])

To resolve the cache names in a non-standard way you can supply a cacheResolver element, see Cache Selection.

3. Caching Service Methods

The typical use case for method caching is when you have Grails service methods that invoke expensive operations such as HTTP gets, web service calls, filesystem IO, etc.

Although you can use the Springcache plugin to cache service methods that query or update GORM domain objects you should consider whether it's more appropriate to use the Hibernate 2nd level cache (see the relevant sections in the Grails documentation). In some cases using Springcache does make sense, e.g. a service that aggregates the results of multiple queries.

Simply add an @Cacheable annotation to methods that should cache their results and a @CacheFlush annotation to methods that should flush caches.

Be aware that the annotations will only have any effect on Spring-managed beans. If you create instances of your class directly rather than getting them from the application context they will not be decorated with caching/flushing behaviour.

Method caching requires AspectJ auto-weaving to be enabled. If you have grails.spring.disable.aspectj.autoweaving = false set in config then method caching will not work. Content caching is unaffected as it uses a different mechanism.

A simple example might be:

PiracyService.groovy

@Cacheable("pirateCache")
def getPirates() {
    // return a list of pirates
}

@Cacheable("pirateCache") def findPirates(name) { // return a particular pirate }

@Cacheable("shipCache") def getShips() { // return a list of ships }

@CacheFlush("pirateCache") void registerNewPirate(Pirate sailor) { // store a new pirate }

@CacheFlush("shipCache") void registerNewShip(Ship ship) { // store a new ship }

@CacheFlush(["pirateCache", "shipCache"]) void registerNewShipWithCrew(Ship ship, Collection<Sailor> crew) { // store a new ship and associated pirates }

This ties the flushes on the register methods to the particular caches they affect, so after calling registerNewPirate the methods getPirates and findPirates will re-populate their cached results but getShips would still use any cached results from previous calls. Calling registerNewShipWithCrew will flush both caches.

It is fine for multiple methods to share the same caches. Both getPirates and findPirates in the example above share the same cache. Cache entries are keyed on target object (the service instance in this case), method name and call parameters so there should be no confusion when using the same caches on multiple methods.

There are various strategies you can adopt in naming and grouping caches, this example shouldn't be seen as definitive.

3.1. Service Method Cache Keys

When a @Cacheable annotation is found on a service method the plugin generates a key using:

Since Grails services are typically Spring singletons the target object is not usually an issue. There's no need to implements equals or hashCode on your service classes unless you are using a different Spring bean scope and need to differentiate between calls made to different instances of the service.

It is, however, vital to ensure that equals and hashCode is properly implemented on all the types used as parameters to cached methods. If this is not done it is very unlikely that the cache will ever be hit.

3.2 Calling Cached Methods Internally

Service method caching is implemented via Spring AOP, which utilises proxies. In practical terms, this means that when depending on a service with a cached method in another service or controller (or anything else for that matter), you actual receive a proxy for the real service. This allows method calls to be intercepted and for caches to be checked or populated.

The implication of this however is that calls to this (implicit or explicit) do NOT go via the proxy.

Consider the following…

class ExampleService {

def nonCachedMethod() { cachedMethod() }

@Cacheable('cachedMethodCache') def cachedMethod() { // do some expensive stuff } }

You may expect that the nonCachedMethod() will use the cache for cachedMethod(), but it won't. The call is made on this which is the actual instance and not the proxy.

Fortunately, there is an easy workaround…

class ExampleService {

def grailsApplication

def nonCachedMethod() { grailsApplication.mainContext.exampleService.cachedMethod() }

@Cacheable('cachedMethodCache') def cachedMethod() { // do some expensive stuff } }

Instead of calling the method on this, we obtain the proxy via the application context (i.e. grailsApplication.mainContext.exampleService) and call the method on that. This way we go through the caching mechanism.

4. Content Caching

The @Cacheable and @CacheFlush annotations can be applied to controller actions and the plugin will then cache the page fragment generated by the controller whether this is done by rendering a GSP, using a MarkupBuilder closure, rendering text directly or whatever. Only successful page renders are cached, so redirects, 404s, errors and so on will not be.

Composing pages so that they can be optimally cached requires some thought. The plugin uses a servlet filter that runs 'inside' the SiteMesh filter provided by Grails. This means that cached output is decorated by SiteMesh and the resulting page can therefore contain uncached content from the SiteMesh template. In addition you can use caching at a modular level to cache the output of controller actions invoked using the g:include tag, or by caching taglib tags. Combining these techniques leads to powerful modular page caching. For example, you can cache the output of the 'main' controller then use g:include tags, or taglib tags, in the SiteMesh layout to include content on the page that is cached separately - and can be flushed separately - from the main body of the page.

4.1. Caching and Flushing with Controller Actions

Example: caching Grails CRUD pages

Grails' standard scaffolded CRUD pages provide a good example of how caching and flushing can be applied. For example, let's take an Album domain class. The scaffolded controller could be annotated like this:

AlbumController.groovy

class AlbumController {
    // the index action is uncached as it just performs a redirect to list
    def index = {
        redirect(action: "list", params: params)
    }

@Cacheable("albumControllerCache") def list = { // standard Grails scaffolding code omitted }

@Cacheable("albumControllerCache") def create = { // standard Grails scaffolding code omitted }

@CacheFlush(["albumControllerCache", "artistControllerCache", "latestControllerCache", "popularControllerCache"]) def save = { // standard Grails scaffolding code omitted }

@Cacheable("albumControllerCache") def show = { // standard Grails scaffolding code omitted }

@Cacheable("albumControllerCache") def edit = { // standard Grails scaffolding code omitted }

@CacheFlush(["albumControllerCache", "latestControllerCache", "popularControllerCache"]) def update = { // standard Grails scaffolding code omitted }

@CacheFlush(["albumControllerCache", "artistControllerCache", "latestControllerCache", "popularControllerCache"]) def delete = { // standard Grails scaffolding code omitted } }

The list, show, create and edit pages are all cached. The show and edit rely on an domain object id parameter and this will be included in the cache key so that /album/show/1 and /album/show/2 are cached separately. The save, update and delete actions will flush caches. Note that in addition to flushing the cache used by the list, show, create and edit actions they are flushing other caches which are content caches for controllers whose output should be refreshed if Album data changes.

4.2. Content Caching and SiteMesh

Example: decorating a cached page with dynamic content using SiteMesh

It is often necessary to have portions of a page be dynamic. A typical example is when something is displayed to logged in users that will be different for each user. Those sorts of page sections are not really candidates for caching. At the same time other parts of the page may well be able to take advantage of caching. For example, if you want to display a "Welcome back $username" type message in page headers while caching the main body of the page you can use SiteMesh templates like this:

grails-app/views/layouts/main.gsp

<html>
    <head>
        <title><g:layoutTitle default="Welcome to My Grails Application"/></title>
        <%-- render the page head from the controller - may be cached --%>
        <g:layoutHead/>
    </head>
    <body>
        <%-- render a "welcome back" header (tags used here are from the Spring Security plugin) --%>
        <g:isLoggedIn>
            <div id="loggedInUser"><g:message code="auth.loggedInAs" args="[loggedInUsername()]" default="Logged in as {0}"/></div>
        </g:isLoggedIn>
        <g:isNotLoggedIn>
            <div id="loginLink"><g:link controller="login"><g:message code="default.login.label" default="Login here"/></g:link></div>
        </g:isNotLoggedIn>

<%-- render the page body from the controller - may be cached --%> <g:layoutBody/> </body> </html>

If the controller action invoked uses @Cacheable everything will work fine because the content of the SiteMesh layout is not cached - only the content generated by the cached action. The SiteMesh template is applied to cached and uncached content alike so the correct username will be displayed to your users even though the main body of the page may have been loaded from a cache.

Example: a modular page using multiple cached sections

One of the most powerful features of page fragment caching is that the generated page can be composed from multiple cached sections. This is accomplished using Grails' g:include tag. For example, in this page the main body of the page is rendered by some controller action and the output of other controllers are included in the SiteMesh layout using the g:include tag:

grails-app/views/layouts/main.gsp

<html>
    <head>
        <title><g:layoutTitle default="Welcome to My Grails Application"/></title>
        <%-- render the page head from the controller - may be cached --%>
        <g:layoutHead/>
    </head>
    <body>
        <%-- render the page body from the controller - may be cached --%>
        <g:layoutBody/>

<div class="sidebar"> <%-- each of these controller actions can be cached separately as well --%> <g:include controller="latest" action="albums"/> <g:include controller="popular" action="albums"/> </div> </body> </html>

LatestController.groovy

@Cacheable("latestAlbums")
def albums = {
    def albums = Album.list(sort: "dateCreated", order: "desc", max: 10)
    [albumInstanceList: albums]
}

LatestController.groovy

@Cacheable("popularAlbums")
def albums = {
    def albums = Album.listOrderByAverageRating(max: 10)
    return [albumInstanceList: albums]
}

If all the caches are hit the final rendered page will be composed of 3 separate cached sections. What is more, each individual section can be flushed without affecting the others so with some thought about how to compose your page and apply your caches you can optimise cache usage without delivering stale data to the user.

4.3. Using Annotations at Class Level

The @Cacheable and @CacheFlush annotations can be applied to controllers at class level. This is more likely useful with @Cacheable but it is certainly possible to apply @CacheFlush at class level so that any action on that controller will flush a set of caches. Any annotation on an individual action will be applied in preference to an annotation at class level, so a class level annotation behaves like a default. An annotation at class level will work with dynamic scaffolded actions so you don't have to generate a concrete action in order to benefit from caching behaviour.

@Cacheable("albumControllerCache")
class AlbumController {

static scaffold = true // all dynamically scaffolded actions will be cached

@Cacheable("albumListCache") def list = { // … }

@CacheFlush(/albumw+Cache/) def save = { // … }

def show = { // … } }

In this example:

4.4. Cache Headers

Content caching in the Springcache plugin attempts to respect any cache-control headers present in the original response. Specifically the plugin will handle certain response headers as follows:

Cache-Control: no-cache

If this header is present in the response the content will not be cached even if there is a @Cacheable annotation present on the controller or action. This allows you to prevent caching in certain circumstances or override the controller-wide caching policy in a particular action.

Cache-Control: max-age=x

If the response is cached the time-to-live of the cache entry is set so that it corresponds to the max-age value in the Cache-Control header. If no such header is present the cache's configured time-to-live is used (see Cache Configuration).

ETag

If the original response set an ETag header Springcache will set the same header if it serves the response from the cache. Additionally, if an incoming request has an If-None-Match header that matches the ETag of the cached response Springcache will send a 304 Not Modified status code and an empty response body instead of the cached response.

Last-Modified

If the original response set a Last-Modified header Springcache will set the same header if it serves the response from the cache. Additionally, if an incoming request has an If-Modified-Since header with a timestamp later than the Last-Modified header of the cached response Springcache will send a 304 Not Modified status code and an empty response body instead of the cached response.

The Cache Headers Plugin

The Springcache plugin integrates well with the Cache Headers plugin. Some examples:

Preventing caching

If you want to prevent Springcache from caching a response in certain circumstances:

@Cacheable("myCache")
def myAction = {
	// …
	if (someConditionHoldsThatMeansThisShouldNotGetCached) {
		cache false
	}
	// …
}

Alternatively you might want to declare @Cacheable at the class level and then exclude a particular action from the cache:

@Cacheable("myCache")
class MyController {

// ...

def myAction = { cache false // … }

Controlling cache expiry

As explained above cache time-to-live will respect the max-age in a cache control header.

@Cacheable("myCache")
def myAction = {
	cache validFor: 3600
	// …
}

In this example the response will be cached with a time-to-live of one hour regardless of the default time-to-live configured on the cache itself.

Sending Not-Modified responses

@Cacheable("myCache")
def show = {
	withCacheHeaders {
		def book = Book.get(params.id)
		etag {
			"${book.ident()}:${book.version}"
		}
		lastModified {
			book.dateCreated ?: book.dateUpdated
		}
		generate {
			render view: "show", model: [item: book]
		}
	}
}

In this example the response will be cached and any subsequent requests that send matching If-Modified-Since and/or If-None-Match headers will be sent a 304 Not Modified response if they hit the cache.

4.5. Content Cache Keys

The Springcache plugin uses an instance of the interface grails.plugin.springcache.key.KeyGenerator to generate the cache key. The default implementation is a bean named springcacheDefaultKeyGenerator which is of type grails.plugin.springcache.web.key.DefaultKeyGenerator. If you want to use a different key generator for a particular action you just need to add the keyGenerator element to the @Cacheable annotation specifying the name of a Spring bean that implements the KeyGenerator interface.

@Cacheable(cache = "albumControllerCache", keyGenerator = "myKeyGenerator")
def list = {
    // …
}

Alternatively you can override the default key generator by redefining the springcacheDefaultKeyGenerator bean in _resources.groovy_.

The keyGenerator element is only for content caching and just works on controllers, it is ignored by the @Cacheable annotation on service methods and taglibs.

grails.plugin.springcache.web.key.DefaultKeyGenerator

The DefaultKeyGenerator generates a key based on the controller name, action name and any request parameters (which can be from a query string, POST body or those added by Grails URL mappings, e.g. the id parameter on a standard show or edit action).

grails.plugin.springcache.web.key.WebContentKeyGenerator

WebContentKeyGenerator is a multi-purpose KeyGenerator implementation that exposes a number of boolean properties that control key generation. All the properties default to false_.

ajax

If _true then keys will differ depending on the presence or absence of the X-Requested-With request header so AJAX requests will be cached separately from regular requests. This is useful when you have an action that renders different content when it is requested via AJAX_.

contentType

If _true keys will differ depending on the requested content format as determined by the format meta-property on HttpServletRequest. This is useful when you use content negotiation in a request so that responses with different formats are cached separately.

See Content Negotiation for more detail.

requestMethod

If true keys will differ depending on the request HTTP method. This is useful for some RESTful controllers (although if different request methods are mapped to different actions you do not need to use this mechanism). GET and HEAD requests are considered the same for the purposes of key generation.

Example configuration

ajaxAwareKeyGenerator(WebContentKeyGenerator) {
	ajax = true
}

contentTypeAwareKeyGenerator(WebContentKeyGenerator) { contentType = true }

4.6. Content Negotiation

By default the key generator used by the page fragment caching filter does not take content negotiation into account. However, if you are caching controller actions that use Grails' withFormat dynamic method to render different content types you will want to cache results separately according to the output format. You can use the WebContentKeyGenerator class to do this. You just need to register a key generator bean with Spring and then annotate any content negotiated actions like this:

grails-app/conf/spring/resources.groovy

mimeTypeAwareKeyGenerator(WebContentKeyGenerator) {
	contentType = true
}

grails-app/controllers/MyController.groovy

@Cacheable(cache = "albumControllerCache", keyGenerator = "mimeTypeAwareKeyGenerator")
def list = {
    def albumList = Album.list()
	withFormat {
		html { [albumList: albumList] }
		xml { render albumList as XML }
		json { render albumList as JSON }
	}
}

4.7. Full Page Caching

The plugin only provides page fragment caching rather than full page caching. Full page caching is very simple to apply using the EhCache-Web library that the Springcache plugin uses. See my blog post here for details.

4.8. TagLib Caching

An alternative to using includes for caching smaller page fragments is to use caching on taglib tags. When a cacheable tag is called, the parameters it is called with from the cache key. If there is no entry in the cache, the tag is executed and the output that it generated is cached (as well as being written to the page). If there is an entry in the cache, the tag is not executed and the cached output is written to the page.

class BlogArticlesTagLib {

static namespace = "blogarticles"

def blogArticlesService

@Cacheable("blogArticlesTagCache") def allArticles = { attrs -> out << "<ul>" blogArticlesService.getArticles(attrs.id).each { out << "<li>${it.title}</li>" } out << "</ul>" } }

When we call the tag like so…

<blogarticles:allArticles id="${blogId}" />

The cache key is formed by the 'id' tag. This tag can be reused across different views without changing the caching semantics. That is, the controller/action that the cacheable tag is called from does not affect the cache key.

Tags with a body

When caching a tag with a body, if there is a cache hit the body will not be executed. Therefore it doesn't make sense to cache a tag that is invoked with a different body unless you are ensuring the right cacheability through the tag parameters (i.e. cache keys).

5. Cache Selection

In some specialised circumstances you may need to programatically select the cache used when a @Cacheable or @CacheFlush annotation is hit. An example might be a multi-tenant application where optimising cache utilisation by caching content for different tenants in their own caches would make sense.

To apply cache selection you need a bean in the Spring context that implements the grails.plugin.springcache.CacheResolver interface. The interface is extremely simple having only one method resolveCacheName(String) which is passed the "base" cache name declared on your annotation and should return the actual cache name to use. You can then add a cacheResolver parameter to @Cacheable and @CacheFlush annotations referencing the bean name of your CacheResolver implementation.

You can override the default CacheResolver used by the plugin by simply redefining the bean springcacheDefaultCacheResolver in _resources.groovy_.

Example usage

A simple example based on the Multi-Tenant plugin. Cached actions should use a different cache depending on the current tenant.

First we define a CacheResolver implementation that will simply append the current tenant id to the base cache name:

import grails.plugin.springcache.CacheResolver
import org.springframework.web.context.request.RequestContextHolder

class MultiTenantCacheResolver implements CacheResolver {

def tenantResolver // a component of the Multi-Tenant plugin, see that plugin's documentation

String resolveCacheName(String baseName) { def request = RequestContextHolder.requestAttributes.currentRequest def tenantId = tenantResolver.getTenantFromRequest(request) "${baseName}-tenant-${tenantId}" } }

Then we need to wire up our cache resolver in the Spring application context in the grails-app/conf/spring/resources.groovy file and wiring in the dependency on the tenantResolver bean provided by the Multi-Tenant plugin.

multiTenantCacheResolver(MultiTenantCacheResolver) {
	tenantResolver = ref("tenantResolver")
}

Finally we just need to reference the multiTenantCacheResolver bean on any annotations in parts of the code that need to be multi-tenant aware:

@Cacheable(cache = "userCache", cacheResolver = "multiTenantCacheResolver")
def list = {
	[users: User.list()] // under the multi-tenant plugin this will only return user instances for the current tenant
}

@CacheFlush(caches = "userCache", cacheResolver = "multiTenantCacheResolver") def save = { def user = new User(params) // … save the new user, redirect, handle errors, etc. }

If you use cache selection when it's not really appropriate it's very easy to get into problems with cache invalidation and stale data.

6. Programmatic Caching and Flushing

Both the servlet filter used for content caching and the AOP aspects used for service method caching use a Grails service to handle caching and flushing. Your application can access this service directly if you need to do any programmatic caching or flushing. The service is called springcacheService and can be auto-injected into your Grails artefacts just like any other Spring bean. The service provides the following methods:

The plugin encourages you to use declarative caching and flushing to maintain a good separation of concerns. Over-using the springcacheService is likely to render your code harder to test and maintain. That said programmatic caching may be necessary in some places but there are some caveats:

7. Cache Configuration

Caches referenced by the annotations can be configured, either in an ehcache.xml (usually kept in the grails-app/conf directory) file, using EhCacheFactoryBean definitions in grails-app/conf/spring/resources.groovy or via Config.groovy. If you do not configure caches individually they will be created on demand using defaults.

Configuring caches with resources.groovy

You can configure caches in grails-app/conf/spring/resources.groovy using instances of Spring's EhCacheFactoryBean class. For example:

grails-app/conf/spring/resources.groovy

pirateCache(EhCacheFactoryBean) { bean ->
    cacheManager = ref("springcacheCacheManager")
    cacheName = "pirateCache"
    // these are just examples of properties you could set
    eternal = false
    diskPersistent = false
    memoryStoreEvictionPolicy = "LRU"
}

You can inherit default cache properties from those defined in Config.groovy by setting the factory bean's parent to 'springcacheDefaultCache'. For example:

pirateCache(EhCacheFactoryBean) { bean ->
    bean.parent = ref("springcacheDefaultCache")
    cacheName = "pirateCache"
    // set any properties unique to this cache
    memoryStoreEvictionPolicy = "LRU"
}

Configuring caches with Config.groovy

The Springcache plugin enables you to define caches in Config.groovy for convenience. For example:

grails-app/conf/Config.groovy

springcache {
    defaults {
        // set default cache properties that will apply to all caches that do not override them
        eternal = false
        diskPersistent = false
    }
    caches {
        pirateCache {
            // set any properties unique to this cache
            memoryStoreEvictionPolicy = "LRU"
        }
    }
}

Under the hood this is simply setting up EhCacheFactoryBean instances in the Spring context, so it is up to you whether you prefer to use resources.groovy or Config.groovy there is not much difference.

The properties shown are just examples, see the EhCacheFactoryBean documentation for full details of all the properties you can set.

8.1. Tips

Flushing content caches with service methods and vice-versa

There is nothing special about the different types of cache so it's perfectly fine to flush a content cache with a @CacheFlush annotation on a service method or a service method cache with a @CacheFlush annotation on a controller action. There's also no reason that you shouldn't use the same cache for both service method and content caching the keys will be quite distinct so this will not be a problem.

Tearing down caches in tests

In integration test and some types of functional test (e.g. Selenium RC tests when not running in remote mode) your tests can have Spring beans automatically injected. You can use this facility to tear down caches between tests. For example:

def springcacheService // auto-injected service bean from plugin

void tearDown() { super.tearDown() springcacheService.flushAll() // only need to do this if your tests are making assertions about hit/miss counts, etc. springcacheService.clearStatistics() }

Disabling

Rather than tearing down caches between tests you may prefer to disable the plugin altogether. This is done by setting the config key springcache.enabled = false which can be done on a per-environment basis. For example:

springcache {
    // cache definitions, etc
}

environments { development { springcache.enabled = false } }

Whilst this makes things simpler I would encourage you to run end-to-end tests and continuous integration in as 'production-like' an environment as possible. If your continuous integration build is running with the plugin enabled you are much less likely to get any surprising behaviour when you release your app to a production environment.

Logging

To see logging from the plugin set the logging level on grails.plugin.springcache in your Config.groovy file.

Response headers

The plugin sets a header X-Springcache-Cached with a value of true or false to indicate whether or not a controller response was served from the cache. This only applies to the "main" request and not to any content included using the g:include tag.

8.2. FAQ

Can I evict only some of the contents of a cache instead of flushing the whole thing?

No. It's not possible to 'reverse engineer' cache keys into the values that were used to generate them so how would you know which keys to evict? If you find yourself asking this question you should consider using more focused caches rather than putting everything into the same bucket. The pursuit of 100% efficiency where no service method or controller action is ever invoked when its contents could conceivably have been served from a cache is subject to the law of diminishing returns. Any time you flush a cache you may well discard some entries that could potentially still have been used but so long as your caches are set up sensibly that's really not something that you should worry about.

My cache config doesn't seem to be working.

Ensure all your config for the Springcache plugin is nested inside a single springcache block in Config.groovy otherwise only the last block will take effect.

Can I programatically disable caching in specific circumstances such as when a user is logged in?

In the case of controller caching you can do so by setting a Cache-Control response header with a value of "no-cache" which can be done manually, or by using the command cache false provided by the Cache Headers plugin. See Cache Headers

Why isn't there a taglib so I can just wrap parts of my page that need caching?

It's something I may add but from a purist point of view I'm not very keen on the idea. Caching is a separate concern from view rendering and the two really shouldn't be mixed up. So far the plugin has deliberately taken a declarative approach to caching which encourages you to maintain a good separation of concerns.

If this is something you really want to see, vote for the issue on JIRA here: "GRAILSPLUGINS-2564":http://jira.codehaus.org/browse/GRAILSPLUGINS-2564

8.3. Upgrading From Earlier Versions

Successive versions of the plugin have introduced some non-backwards compatible changes. If you are upgrading from an earlier version you will need to consider the following:

Upgrading from 1.2.* to 1.3:

Upgrading from 1.1.* to 1.2:

From pre 1.1: