The CacheFactory
static factory methods allow you to access all Coherence caches and services. These methods, (such as getCache
), delegate to a ConfigurableCacheFactory
interface, which is pluggable by using 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 by using the class-scheme element. Coherence can instantiate these classes in two ways: it can create a new instance by using the new operator, or it can invoke a user-provided factory method.
For some applications, it may be useful 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 standalone JVM, as these CacheStore
objects typically need to be configured with data sources, connection pools, and so on. 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:
It can instantiate its own ApplicationContext
with a provided configuration file. This is useful for cache servers that require beans from a Spring container.
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 XML code should be placed in the operational override file (tangosol-coherence-override.xml
):
Example 10-1 Configuring the Cache to use SpringAwareCacheFactory in the Override File
<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.
As an alternative to using the configuration file, the SpringAwareCacheFactory
can be configured programmatically as illustrated inExample 10-2:
Example 10-2 Configuring a SpringAwareCacheFactory Programmatically
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:
Example 10-3 Defining a SpringAwareCacheFactory in an Application Context
<bean id="cacheFactory" class="com.tangosol.coherence.spring.SpringAwareCacheFactory"> </bean>
Taking this a step further, the Coherence CacheFactory
can be configured inside of the application context:
Example 10-4 Configuring a CacheFactory in an 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 as in Example 10-5. Note that the EntityCacheStore
is scoped as prototype. This is done because Coherence will manage the lifecycle of the bean when it is retrieved from Spring, just as if Coherence had instantiated the object using new
.
Example 10-5 Configuring a CacheStore in an Application Context
<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>
Coherence can use the entityCacheStore
bean as illustrated in Example 10-6. By using the init-param
element, setter injection can be used to set properties on the bean retrieved from Spring. In the above example, the bean will have the method setEntityName
invoked with the cache name before it is used by Coherence.
Example 10-6 Configuring Setter Injection to Set Properties on the Bean
<?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>
Example 10-7 lists the source for SpringAwareCacheFactory
. It requires Coherence 3.4.x and Spring 2.x.
Example 10-7 SpringAwareCacheFactory.java
/* * SpringAwareCacheFactory.java * * Copyright 2001-2007 by Oracle. All rights reserved. * * Oracle is a registered trademarks of Oracle Corporation and/or its affiliates. * * This software is the confidential and proprietary information of * Oracle Corporation. You shall not disclose such confidential and * proprietary information and shall use it only in accordance with the * terms of the license agreement you entered into with Oracle. * * This notice may not be removed or altered. */ package com.tangosol.coherence.spring; import com.tangosol.net.BackingMapManagerContext; import com.tangosol.net.DefaultConfigurableCacheFactory; import com.tangosol.run.xml.SimpleElement; import com.tangosol.run.xml.XmlElement; import com.tangosol.run.xml.XmlHelper; import com.tangosol.util.ClassHelper; import java.util.Iterator; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; /** * SpringAwareCacheFactory provides a facility to access caches declared * in a "cache-config.dtd" compliant configuration file, similar to its super * class {@link DefaultConfigurableCacheFactory}. In addition, this factory * provides the ability to reference beans in a Spring application context * by using the use of a class-scheme element. * * <p>This factory can be configured to start its own Spring application * context from which to retrieve these beans. This can be useful for standalone * JVMs such as cache servers. It can also be configured at runtime with a * preconfigured Spring bean factory. This can be useful for Coherence * applications running in an environment that is itself responsible for starting * the Spring bean factory, such as a web container. * * @see #instantiateAny(CacheInfo, XmlElement, BackingMapManagerContext, ClassLoader) * * @author pperalta Jun 14, 2007 */ public class SpringAwareCacheFactory extends DefaultConfigurableCacheFactory implements BeanFactoryAware { // ----- constructors ------------------------------------------------- /** * Construct a default DefaultConfigurableCacheFactory using the * default configuration file name. */ public SpringAwareCacheFactory() { super(); } /** * Construct a SpringAwareCacheFactory using the specified path to * a "cache-config.dtd" compliant configuration file or resource. This * will also create a Spring ApplicationContext based on the supplied * path to a Spring compliant configuration file or resource. * * @param sCacheConfig location of a cache configuration * @param sAppContext location of a Spring application context */ public SpringAwareCacheFactory(String sCacheConfig, String sAppContext) { super(sCacheConfig); azzert(sAppContext != null && sAppContext.length() > 0, "Application context location required"); m_beanFactory = sCacheConfig.startsWith("file:") ? (BeanFactory) new FileSystemXmlApplicationContext(sCacheConfig) : new ClassPathXmlApplicationContext(sAppContext); // register a shutdown hook so the bean factory cleans up // upon JVM exit ((AbstractApplicationContext) m_beanFactory).registerShutdownHook(); } /** * Construct a SpringAwareCacheFactory using the specified path to * a "cache-config.dtd" compliant configuration file or resource and * the supplied Spring BeanFactory. * * @param sPath the configuration resource name or file path * @param beanFactory Spring BeanFactory used to load Spring beans */ public SpringAwareCacheFactory(String sPath, BeanFactory beanFactory) { super(sPath); m_beanFactory = beanFactory; } // ----- extended methods ----------------------------------------------- /** * Create an Object using the "class-scheme" element. * <p/> * In addition to the functionality provided by the super class, * this will retreive an object from the configured Spring BeanFactory * for class names that use the following format: * <pre> * <class-name>spring-bean:sampleCacheStore</class-name> * </pre> * * Parameters may be passed to these beans by using setter injection as well: * <pre> * <init-params> * <init-param> * <param-name>setEntityName</param-name> * <param-value>{cache-name}</param-value> * </init-param> * </init-params> * </pre> * * Note that Coherence will manage the lifecycle of the instantiated Spring * bean, therefore any beans that are retreived using this method should be * scoped as a prototype in the Spring configuration file, for example: * <pre> * <bean id="sampleCacheStore" * class="com.company.SampleCacheStore" * scope="prototype"/> * </pre> * * @param info the cache info * @param xmlClass "class-scheme" element. * @param context BackingMapManagerContext to be used * @param loader the ClassLoader to instantiate necessary classes * * @return a newly instantiated Object * * @see DefaultConfigurableCacheFactory#instantiateAny( * CacheInfo, XmlElement, BackingMapManagerContext, ClassLoader) */ protected Object instantiateAny(CacheInfo info, XmlElement xmlClass, BackingMapManagerContext context, ClassLoader loader) { if (translateSchemeType(xmlClass.getName()) != SCHEME_CLASS) { throw new IllegalArgumentException( "Invalid class definition: " + xmlClass); } String sClass = xmlClass.getSafeElement("class-name").getString(); if (sClass.startsWith(SPRING_BEAN_PREFIX)) { String sBeanName = sClass.substring(SPRING_BEAN_PREFIX.length()); azzert(sBeanName != null && sBeanName.length() > 0, "Bean name required"); XmlElement xmlParams = xmlClass.getElement("init-params"); XmlElement xmlConfig = null; if (xmlParams != null) { xmlConfig = new SimpleElement("config"); XmlHelper.transformInitParams(xmlConfig, xmlParams); } Object oBean = getBeanFactory().getBean(sBeanName); if (xmlConfig != null) { for (Iterator iter = xmlConfig.getElementList().iterator(); iter.hasNext();) { XmlElement xmlElement = (XmlElement) iter.next(); String sMethod = xmlElement.getName(); String sParam = xmlElement.getString(); try { ClassHelper.invoke(oBean, sMethod, new Object[]{sParam}); } catch (Exception e) { ensureRuntimeException(e,"Could not invoke " + sMethod + "(" + sParam + ") on bean " + oBean); } } } return oBean; } else { return super.instantiateAny(info, xmlClass, context, loader); } } /** * Get the Spring BeanFactory used by this CacheFactory * @return the Spring {@link BeanFactory} used by this CacheFactory */ public BeanFactory getBeanFactory() { azzert(m_beanFactory != null, "Spring BeanFactory == null"); return m_beanFactory; } /** * Set the Spring BeanFactory used by this CacheFactory * @param beanFactory the Spring {@link BeanFactory} used by this CacheFactory */ public void setBeanFactory(BeanFactory beanFactory) { m_beanFactory = beanFactory; } // ----- data fields ---------------------------------------------------- /** * Spring BeanFactory used by this CacheFactory */ private BeanFactory m_beanFactory; /** * Prefix used in cache configuration "class-name" element to indicate * this bean is in Spring */ private static final String SPRING_BEAN_PREFIX = "spring-bean:"; }