Springは、Java EEアプリケーションの構築および実行を目的としたプラットフォームですこの章では、Springプラットフォーム上で実行されるアプリケーションが使用するOracle Coherenceキャッシュの構成方法について説明します。
Coherenceの静的なファクトリ・メソッドCacheFactory
を使用すると、Coherenceのすべてのキャッシュおよびサービスにアクセスできます。これらのメソッド(getCache
など)は、ConfigurableCacheFactory
インタフェースに委任しますが、このインタフェースは、CacheFactory.setConfigurableCacheFactory
メソッドまたはオペレーション・オーバーライド・ファイル(tangosol-coherence-override.xml
)を使用することで、プラッガブルになります。
Coherenceキャッシュ構成ファイル(coherence-cache-config.xml
)には、class-scheme
要素が含まれており、そこでCacheStore
やMapListener
などの独自のCoherenceインタフェースの実装を指定できます。Coherenceでは、実装を2つの方法でインスタンス化できます。新しい演算子を使用して新しいインスタンスを作成する方法と、ユーザーが指定したファクトリ・メソッドを起動する方法です。
アプリケーションによっては、独自のインスタンスを作成するよりも、CoherenceがSpringのBeanFactory
インスタンスからclass-scheme
要素で構成されているオブジェクトを取得するほうが便利な場合があります。これは、CacheStore
オブジェクトをスタンドアロンJVMで実行するように構成されているキャッシュ・サーバーでは特に有効です。これらのCacheStore
オブジェクトには通常、データソース、接続プールなども合せて構成する必要があるからです。Springでは、単純なJavaオブジェクトのデータソースを簡単に構成できます。
SpringAwareCacheFactory
インタフェースは、クラス・スキームBeanのインスタンス化をSpringのBeanFactory
インスタンスに委任する機能を持つカスタムのConfigurableCacheFactory
です。これには、2つの操作モードがあります。
実行時にBeanFactory
インスタンスを提供できます。これは、ずでに既存のBeanFactory
インスタンスがあるコンテナで実行されているCoherenceアプリケーションで役立ちます。
SpringAwareCacheFactory
インスタンスを使用するようにCoherenceを構成するには、例4-1のXMLコードをオペレーション・オーバーライド・ファイル(tangosol-coherence-override.xml
)に配置する必要があります。デフォルトでは、これにより、coherence-cache-config.xml
がキャッシュ構成ファイルとして、application-context.xml
がSpring構成ファイルとして指定されます。
例4-1 SpringAwareCacheFactoryを使用するキャッシュの構成
... <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> ...
構成ファイルを使用するかわりに、例4-2に示すように、SpringAwareCacheFactory
インスタンスをプログラムで構成することもできます。
例4-2 プログラムでのSpringAwareCacheFactoryの構成
BeanFactory bf = ...
SpringAwareCacheFactory scf = new SpringAwareCacheFactory();
scf.setBeanFactory(bf);
CacheFactory.setConfigurableCacheFactory(scf);
SpringAwareCacheFactory
インスタンスはBeanFactoryAware
であるため、例4-3に示すようにアプリケーション・コンテキストでも定義できます。
例4-3 アプリケーション・コンテキストでのSpringAwareCacheFactoryインスタンスの定義
<bean id="cacheFactory" class="com.tangosol.coherence.spring.SpringAwareCacheFactory"> </bean>
さらに進化させて、Coherence CacheFactory
インスタンスを例4-4に示すようにアプリケーション・コンテキスト内で構成できます。
例4-4 アプリケーション・コンテキストでのCacheFactoryインスタンスの構成
<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>
アプリケーション・コンテキストで、例4-5に示すようにCacheStore
インスタンスを構成できます。EntityCacheStore
インスタンスは、prototype
として範囲指定されています。この値が指定されるのは、Coherenceでは、new
演算子を使用してオブジェクトをインスタンス化した場合と同様に、Springから取得したBeanのライフサイクルも管理されるためです。
例4-5 アプリケーション・コンテキストでのCacheStoreインスタンスの構成
<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では、例4-6に示すようにentityCacheStore
Beanを使用できます。init-param
要素を使用することにより、setterインジェクションを使用して、Springから取得したBeanのプロパティを設定できます。このBeanは、キャッシュ名を指定したsetEntityName
メソッドを起動してからCoherenceで使用されます。
例4-6 Beanのプロパティを設定するsetterインジェクションの構成
<?xml version="1.0"?> <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd"> <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>
例4-7は、SpringAwareCacheFactory
のJavaソース・コードのリストです。これには、少なくともCoherence 3.4.nとSpring 2.nが必要です。
例4-7 Spring対応キャッシュ・ファクトリの更新済サンプル
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 * through the use of a class-scheme element. * * 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 run time 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) * */ 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(sAppContext) : 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. * * 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: * * <class-name>spring-bean:sampleCacheStore</class-name> * * * Parameters may be passed to these beans through setter injection as well: * * <init-params> * <init-param> * <param-name>setEntityName</param-name> * <param-value>{cache-name}</param-value> * </init-param> * </init-params> * * * Note that Coherence will manage the lifecycle of the instantiated Spring * bean, therefore any beans that are retrieved using this method should be * scoped as a prototype in the Spring configuration file, for example: * * <bean id="sampleCacheStore" * class="com.company.SampleCacheStore" * scope="prototype"/> * * * @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) */ public 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:"; }