Declarative Caching Services for Spring
Pages: 1, 2, 3, 4

How Declarative Caching Services Work

Declarative Caching Services uses run-time method interception to deliver transparent, code-free caching and cache flushing to Spring-managed beans. Configuration simply involves selecting which methods should be intercepted and how caching services should be applied to those methods. The following is a quick overview of how declarative caching services work.

The activity diagram in Figure 1 shows how the caching method interceptor works:

Caching in action
Figure 1. Caching in action

The caching method interceptor first generates a unique key using the signature of the intercepted method and the provided parameter values. Then, the interceptor searches in the cache for an object stored under the generated key. If an object is found, it is immediately returned to the client, bypassing the execution of the intercepted method. If the interceptor does not find any value in the cache, it executes the intercepted method, stores the return value in the cache (using the generated key), and returns the cached object to the client. Keys for cache entries are automatically generated through pluggable key generators. Currently, only one strategy is provided, HashCodeCacheKeyGenerator, which creates unique keys based on the hash codes of the intercepted method and its parameters. Key generators can be created easily by implementing the interface CacheKeyGenerator.

The activity diagram in Figure 2 shows how the cache-flushing method interceptor works:

Cache flushing in action
Figure 2. Cache flushing in action

The cache-flushing method interceptor can be configured to flush a cache before or after the intercepted method is executed. The interceptor can flush one or more regions of a cache, or the whole cache, depending on how it is configured and which cache provider is being used.

Configuring Declarative Caching Services

Declarative Caching Services provides a short, simple, and straightforward configuration based on Spring 2.0's support for XML namespaces. Each cache provider has its own namespace that needs to be declared in the Spring IoC container configuration. The following example illustrates how to declare the coherence namespace and how to specify its location:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   
                        
xmlns:coherence="http://www.springmodules.org/schema/coherence"

  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        
                        
http://www.springmodules.org/schema/coherence http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd">
                      

Before setting up the Spring beans that will be the target of caching services, we need to include a couple system-wide configuration settings that influence how caching services behave:

<coherence:config failQuietly="false" 

                  serializableFactory="XSTREAM" />

Caching is an orthogonal concern with the primary goal of improving the performance of an application transparently. Caching should not affect the core business logic or change the behavior of an application. If caching fails, the application should not stop its execution, especially in production. On the other hand, in certain cases you would want your application to stop running for any major or minor malfunction, including caching failures—for example, when performing integration tests during development and you must find any configuration error before placing your application in production.

The property failQuietly gives developers the power to decide whether or not a caching failure should stop the execution of an application. When this property is set to true, any caching failure will not affect the application at all. Its default value is false.

Once caching is up and running, you are going to find cases when you need to store cached objects in the file system or replicate changes in the cache across nodes in a cluster. Cache providers are capable of performing those functions with the help of Java serialization, which implies that the objects to be stored in the cache should implement the interface java.io.Serializable.

Such a requirement imposes a problem when you need to store in the cache objects that are not serializable and that you do not have control of (for example, objects generated by JAXB.) The property serializableFactory provides a solution to this problem by forcing serialization on non-serializable objects. Only one strategy is provided, XStreamSerializableFactory which uses XStream to serialize objects to XML before storing them in the cache. A new strategy using JBoss Serialization will be ready by the time you read this article.

An alternative to force object serialization is to use AspectJ's inter-type declarations to make classes implement java.io.Serializable. The following example assumes the class Customer is not serializable and needs to be stored in a clustered cache:

public aspect SerializationAspect {

  declare parents : Customer implements java.io.Serializable;

}

For more information about inter-type declarations or AspectJ in general, refer to the AspectJ documentation.

Declarative Caching Services provides different configuration strategies giving developers the opportunity to choose the strategy that best suites the needs of their applications. The following sections describe each of the provided configuration strategies.

Pages: 1, 2, 3, 4

Next Page »