CacheFactory Spring Integration

All access to Coherence caches and services happen through CacheFactory static factory methods. These methods (such as getCache) delegate to a ConfigurableCacheFactory interface, which is pluggable via CacheFactory.setConfigurableCacheFactory or the operational override file (tangosol-coherence-override.xml.)

In the Coherence cache configuration file (coherence-cache-config.xml) hooks are provided for end users to provide their own implementations of Coherence interfaces, such as CacheStore and MapListener. This is configured via a class-scheme. Coherence can instantiate these classes in two ways: it can create a new instance via the new operator, or it can invoke a user provided factory method.

For some applications, it would be useful to allow for Coherence to retrieve objects configured in a class-scheme from a Spring BeanFactory instead of creating its own instance. This is especially true for cache servers configured with CacheStore objects running in a stand-alone JVM, as these CacheStore objects typically need to be configured with data sources, connection pools, etc. Spring is well known for its ability to provide easy configuration of data sources for plain Java objects.

SpringAwareCacheFactory is a custom ConfigurableCacheFactory which has the ability to delegate class-scheme bean instantiations to a Spring BeanFactory. It has two modes of operation:

  1. It can instantiate its own ApplicationContext with a provided configuration file. This is useful for cache servers that require beans from a Spring container.
  1. A BeanFactory can be provided to it at runtime. This is useful for Coherence applications running in a container that already has an existing BeanFactory.

To configure Coherence to use the SpringAwareCacheFactory, the following should be placed in the operational override file (tangosol-coherence-override.xml):

<configurable-cache-factory-config>
  <class-name system-property="tangosol.coherence.cachefactory">
    com.tangosol.coherence.spring.SpringAwareCacheFactory
  </class-name>
  <init-params>
    <init-param>
      <param-type>java.lang.String</param-type>
      <param-value system-property="tangosol.coherence.cacheconfig">
        coherence-cache-config.xml
      </param-value>
    </init-param>
    <init-param id="1">
      <param-type>java.lang.String</param-type>
      <param-value system-property="tangosol.coherence.springconfig">
        application-context.xml
      </param-value>
    </init-param>
  </init-params>
</configurable-cache-factory-config>

This will, by default, use coherence-cache-config.xml as the cache configuration file and application-context.xml as the Spring configuration file.

Alternatively, it can be configured via code:

BeanFactory             bf  = ...
SpringAwareCacheFactory scf = new SpringAwareCacheFactory();
        
scf.setBeanFactory(bf);
CacheFactory.setConfigurableCacheFactory(scf);

Since the SpringAwareCacheFactory is BeanFactoryAware, it can also be defined in an application context:

<bean id="cacheFactory"
      class="com.tangosol.coherence.spring.SpringAwareCacheFactory">
</bean>

Taking IoC a step further, the Coherence CacheFactory can be configured inside of the application context:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetClass" value="com.tangosol.net.CacheFactory"/>
  <property name="targetMethod" value="setConfigurableCacheFactory"/>
  <property name="arguments" ref="cacheFactory"/>
</bean>

The application context may have a CacheStore configured:

<bean id="dataSource" class="...">
...
</bean>

<bean id="sessionFactory" class="...">
  <property name="dataSource" ref="dataSource"/>
  ...
</bean>
  
<bean id="entityCacheStore" 
      class="com.company.app.EntityCacheStore"
      scope="prototype">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

Note that the CacheStore is scoped as prototype. This is done because Coherence will manage the lifecycle of the bean once it is retrieved from Spring, just as if Coherence had instantiated the object using new.

Coherence can use the entityCacheStore bean as such:

<?xml version="1.0"?>

<!DOCTYPE cache-config SYSTEM "cache-config.dtd">

<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>com.company.app.domain.*</cache-name>
      <scheme-name>distributed-domain</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>

  <caching-schemes>
    <distributed-scheme>
      <scheme-name>distributed-domain</scheme-name>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <internal-cache-scheme>
            <local-scheme />
          </internal-cache-scheme>
          <cachestore-scheme>
            <class-scheme>
              <class-name>spring-bean:entityCacheStore</class-name>
              <init-params>
                <init-param>
                  <param-name>setEntityName</param-name>
                  <param-value>{cache-name}</param-value>
                </init-param>
              </init-params>
            </class-scheme>
          </cachestore-scheme>
          <write-delay>5s</write-delay>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes>
</cache-config>

Via the use of init-param the bean retrieved from Spring can have properties set on it via setter injection. In the above example, the bean will have the method setEntityName invoked with the cache name before it is used by Coherence.

Attached to this document is the source for SpringAwareCacheFactory. It requires Coherence 3.3.x and Spring 2.x.


Attachments:
SpringAwareCacheFactory.java (text/plain)