I'm on the verge of releasing a new version of the
Springcache plugin that will feature a pretty cool new annotation-driven page fragment caching feature based on
Ehcache-web. However one of the things that came up during discussions on the mailing list was full page caching. I mentioned that it was pretty straightforward and promised to blog about how to do it, so…
Install Ehcache-web
Add the following to your dependencies in BuildConfig.groovy:
runtime("net.sf.ehcache:ehcache-web:2.0.0") {
excludes "ehcache-core"
}
Install Grails templates
Run:
grails install-templates
Set up a page caching filter
Edit
src/templates/war/web.xml and add this to the
filters section:
<filter>
<filter-name>MyPageCachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
<init-param>
<param-name>cacheName</param-name>
<param-value>myPageCache</param-value>
</init-param>
</filter>
And this as the
first entry in the
filter-mappings section:
<filter-mapping>
<filter-name>MyPageCachingFilter</filter-name>
<url-pattern>/controller/action/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Configure the cache
Unfortunately you can't configure the cache in
grails-app/conf/spring/resources.groovy using
EhCacheFactoryBean instances as the servlet filter initialises before the Spring context. The cache definitions need to be added to a
ehcache.xml which would normally be placed in
grails-app/conf. Here is an example that works for the filter definitions above:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="10"
overflowToDisk="true"
/>
<cache name="myPageCache"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
</ehcache>
You will need to add another
filter and
filter-mapping and potentially another cache for each URL pattern you want to cache separately.
Full page caching is fine for simple pages but isn't as flexible as fragment caching. For example, any authenticated state (such as a
"Welcome back xxx" label) on the page would get cached across all users. Because Grails uses
Sitemesh and has the
<g:include> tag for including output from other controllers a fragment caching solution is a good fit. The 1.2 release of the Springcache plugin will add fragment caching functionality. However, I can imagine using full-page caching like this for things like RSS feeds.