Статьи

Как Распределить Весенние Бобы, Используя Согласованность

В этой статье показано, как распространять компоненты 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: СКАЧАТЬ

OTV_Spring_Coherence