В этой статье показано, как распространять компоненты Spring с помощью Coherence. В приведенном ниже примере приложения был создан новый кластер с именем OTV и распределенный bean-компонент с использованием объекта кэша с именем user-map. Он был распределен между двумя членами кластера.
Используемые технологии:
JDK 1.6.0_21
Spring 3.0.5
Maven 3.0.2
Согласованность 3.7.0
SolarisOS 5.10
ШАГ 1: СОЗДАТЬ ПРОЕКТ MAVEN
Maven проект создается как показано ниже. (Его можно создать с помощью Maven или IDE Plug-in).
ШАГ 2: СКАЧАТЬ КОГЕРЕНТНЫЙ ПАКЕТ
Пакет Coherence загружается через http://www.oracle.com/technetwork/middleware/coherence/downloads/index.html
ШАГ 3: БИБЛИОТЕКИ
Во-первых, Spring-зависимости добавляются в pom.xml Maven.
<!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency>
Библиотека Coherence устанавливается в локальный репозиторий Maven, а ее описание добавляется в pom.xml, как показано ниже. Также, если maven не используется, файл coherence.jar можно добавить в classpath.
<!-- Coherence library(from local repository) --> <dependency> <groupId>com.tangosol</groupId> <artifactId>coherence</artifactId> <version>3.7.0</version> </dependency>
Для создания runnable-jar , ниже плагин может быть использован.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.3.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.otv.exe.Application</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
ШАГ 4: СОЗДАТЬ otv-coherence-cache-config.xml
otv-coherence-cache-config.xml содержит конфигурацию кэширования (распределенную или реплицированную) и конфигурацию отображения схемы кэширования. Созданная конфигурация кэша должна быть добавлена в coherence-cache-config.xml .
<?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>user-map</cache-name> <scheme-name>MapDistCache</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>MapDistCache</scheme-name> <service-name>MapDistCache</service-name> <backing-map-scheme> <local-scheme> <unit-calculator>BINARY</unit-calculator> </local-scheme> </backing-map-scheme> <autostart>true</autostart> </distributed-scheme> </caching-schemes> </cache-config>
ШАГ 5: СОЗДАЙТЕ tangosol-coherence-override.xml
tangosol-coherence-override.xml содержит конфигурацию кластера, идентификатора члена и настраиваемой фабрики кэша. Также под конфигурационным xml файлом показан первый член кластера.
tangosol-coherence-override.xml для первого члена кластера:
<?xml version='1.0'?> <coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd"> <cluster-config> <member-identity> <cluster-name>OTV</cluster-name> <!-- Name of the first member of the cluster --> <role-name>OTV1</role-name> </member-identity> <unicast-listener> <well-known-addresses> <socket-address id="1"> <!-- IP Address of the first member of the cluster --> <address>x.x.x.x</address> <port>8089</port> </socket-address> <socket-address id="2"> <!-- IP Address of the second member of the cluster --> <address>y.y.y.y</address> <port>8089</port> </socket-address> </well-known-addresses> <!-- Name of the first member of the cluster --> <machine-id>OTV1</machine-id> <!-- IP Address of the first member of the cluster --> <address>x.x.x.x</address> <port>8089</port> <port-auto-adjust>true</port-auto-adjust> </unicast-listener> </cluster-config> <configurable-cache-factory-config> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value system-property="tangosol.coherence.cacheconfig"> otv-coherence-cache-config.xml </param-value> </init-param> </init-params> </configurable-cache-factory-config> </coherence>
tangosol-coherence-override.xml для второго члена кластера:
<?xml version='1.0'?> <coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd"> <cluster-config> <member-identity> <cluster-name>OTV</cluster-name> <!-- Name of the second member of the cluster --> <role-name>OTV2</role-name> </member-identity> <unicast-listener> <well-known-addresses> <socket-address id="1"> <!-- IP Address of the first member of the cluster --> <address>x.x.x.x</address> <port>8089</port> </socket-address> <socket-address id="2"> <!-- IP Address of the second member of the cluster --> <address>y.y.y.y</address> <port>8089</port> </socket-address> </well-known-addresses> <!-- Name of the second member of the cluster --> <machine-id>OTV2</machine-id> <!-- IP Address of the second member of the cluster --> <address>y.y.y.y</address> <port>8089</port> <port-auto-adjust>true</port-auto-adjust> </unicast-listener> </cluster-config> <configurable-cache-factory-config> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value system-property="tangosol.coherence.cacheconfig"> otv-coherence-cache-config.xml</param-value> </init-param> </init-params> </configurable-cache-factory-config> </coherence>
ШАГ 6: СОЗДАНИЕ applicationContext.xml
applicationContext.xml создан.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Beans Declaration --> <bean id="User" class="com.otv.user.User"></bean> <bean id="CacheService" class="com.otv.srv.CacheService"></bean> <bean id="CacheUpdater" class="com.otv.exe.CacheUpdater"> <property name="user" ref="User" /> <property name="cacheService" ref="CacheService" /> </bean> </beans>
ШАГ 7: СОЗДАТЬ ВЕСНУЮ ФАСОЛЬ
Новый бин User Spring создан. Этот компонент будет распределен между двумя узлами в кластере OTV . Для сериализации был реализован интерфейс java.io.Serializable , но PortableObject может быть реализован для повышения производительности.
package com.otv.user; import java.io.Serializable; /** * @author onlinetechvision.com * @since 15 Oct 2011 * @version 1.0.0 * */ public class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private String surname; public User(String name, String surname) { this.name = name; this.surname = surname; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } @Override public String toString() { StringBuffer strBuff = new StringBuffer(); strBuff.append("name : ").append(name); strBuff.append(", surname : ").append(surname); return strBuff.toString(); } }
ШАГ 8: СОЗДАЙТЕ ИНТЕРФЕЙС ICacheService
Новый интерфейс ICacheService создан для уровня обслуживания.
package com.otv.srv; import com.tangosol.net.NamedCache; public interface ICacheService { public NamedCache getCache(); public void addToCache(Object key, Object value); public void deleteFromCache(Object key); }
ШАГ 9: СОЗДАТЬ CacheService
CacheService создается для уровня обслуживания путем реализации ICacheService .
package com.otv.srv; import org.apache.log4j.Logger; import com.otv.listener.UserMapListener; import com.tangosol.net.CacheFactory; import com.tangosol.net.NamedCache; /** * @author onlinetechvision.com * @since 15 Oct 2011 * @version 1.0.0 * */ public class CacheService implements ICacheService { private static Logger log = Logger.getLogger(CacheService.class); private NamedCache cache = null; private static final String USER_MAP = "user-map"; private static final long LOCK_TIMEOUT = -1; public CacheService() { cache = CacheFactory.getCache(USER_MAP); cache.addMapListener(new UserMapListener()); } public NamedCache getCache() { return cache; } public void setCache(NamedCache cache) { this.cache = cache; } public void addToCache(Object key, Object value) { // key is locked cache.lock(key, LOCK_TIMEOUT); try { // application logic cache.put(key, value); } finally { // key is unlocked cache.unlock(key); } } public void deleteFromCache(Object key) { // key is locked cache.lock(key, LOCK_TIMEOUT); try { // application logic cache.remove(key); } finally { // key is unlocked cache.unlock(key); } } }
ШАГ 10: СОЗДАТЬ USERMAPLISTENER IMPL CLASS
Новый класс UserMapListener создан. Этот слушатель получает распределенные события пользовательской карты .
package com.otv.listener; import org.apache.log4j.Logger; import com.tangosol.util.MapEvent; import com.tangosol.util.MapListener; /** * @author onlinetechvision.com * @since 15 Oct 2011 * @version 1.0.0 * */ public class UserMapListener implements MapListener { private static Logger logger = Logger.getLogger(UserMapListener.class); public void entryDeleted(MapEvent me) { logger.debug("Deleted Key = " + me.getKey() + ", Value = " + me.getOldValue()); } public void entryInserted(MapEvent me) { logger.debug("Inserted Key = " + me.getKey() + ", Value = " + me.getNewValue()); } public void entryUpdated(MapEvent me) { // logger.debug("Updated Key = " + me.getKey() + ", New_Value = " + me.getNewValue() + ", Old Value = " + me.getOldValue()); } }
ШАГ 11: СОЗДАТЬ CacheUpdater
Класс CacheUpdater создан для добавления новой записи в кэш и отслеживания содержимого кеша.
package com.otv.exe; import java.util.Collection; import org.apache.log4j.Logger; import com.otv.srv.ICacheService; import com.otv.user.User; /** * @author onlinetechvision.com * @since 15 Oct 2011 * @version 1.0.0 * */ public class CacheUpdater implements Runnable { private static Logger log = Logger.getLogger(CacheUpdater.class); ICacheService cacheService; User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public ICacheService getCacheService() { return cacheService; } public void setCacheService(ICacheService cacheService) { this.cacheService = cacheService; } public void run() { //New User are created... //Entries which will be inserted via first member of the cluster so before the project is built // in order to deploy first member of the cluster, this code block should be opened... getUser().setName("Bruce"); getUser().setSurname("Willis"); //Entries are added to cache... getCacheService().addToCache("user1", getUser()); // //New User are created... // //Entries which will be inserted via second member of the cluster so before the project is built // // in order to deploy second member of the cluster, this code block should be opened... // getUser().setName("Clint"); // getUser().setSurname("Eastwood"); // // //Entries are added to cache... // getCacheService().addToCache("user2", getUser()); //Cache Entries are printed... printCacheEntries(); } private void printCacheEntries() { Collection<User> userCollection = null; try { while(true) { userCollection = (Collection<User>)getCacheService().getCache().values(); for(User user : userCollection) { log.debug("Cache Content : "+user); } Thread.sleep(10000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
ШАГ 12: СОЗДАЙТЕ Заявку
Класс приложения создан для запуска приложения.
package com.otv.exe; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author onlinetechvision.com * @since 15 Oct 2011 * @version 1.0.0 * */ public class Application { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); CacheUpdater cacheUpdater = (CacheUpdater) context.getBean("CacheUpdater"); cacheUpdater.run(); } }
ШАГ 13: СТРОИМ ПРОЕКТ
После сборки проекта OTV_Spring_Coherence будет создан файл OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar .
Важное примечание: Члены кластера имеют разные конфигурации для Coherence, поэтому проект должен быть построен отдельно для каждого участника.
ШАГ 14: ЗАПУСК ПРОЕКТА ПЕРВОГО ЧЛЕНА КЛАСТЕРА
После того, как созданный файл OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar запущен на элементах кластера, в консоли первого участника будут показаны следующие выходные журналы:
--A new cluster is created and First Member joins the cluster and adds a new entry to the cache. 15.10.2011 00:52:48 DEBUG (UserMapListener.java:23) - Inserted Key = user1, Value = name : Bruce, surname : Willis 15.10.2011 00:52:48 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis ....... --Second Member joins the cluster and adds a new entry to the cache. 15.10.2011 00:53:13 DEBUG (UserMapListener.java:23) - Inserted Key = user2, Value = name : Clint, surname : Eastwood ....... --After second member adds a new entry, cache content is shown as below : 15.10.2011 00:53:19 DEBUG (CacheUpdater.java:51) - Cache Content : name : Clint, surname : Eastwood 15.10.2011 00:53:19 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis
Консоль второго члена:
--After Second Member joins the cluster and adds a new entry to the cache, cache content is shown as below and the members has got same entries :. 15.10.2011 00:53:13 DEBUG (UserMapListener.java:23) - Inserted Key = user2, Value = name : Clint, surname : Eastwood 15.10.2011 00:53:14 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis 15.10.2011 00:53:15 DEBUG (CacheUpdater.java:51) - Cache Content : name : Clint, surname : Eastwood
ШАГ 15: СКАЧАТЬ