Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Distribute Spring Beans by Using Coherence

DZone's Guide to

How to Distribute Spring Beans by Using Coherence

· Java Zone
Free Resource

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

This article shows how to distribute Spring beans by using Coherence. In below sample application, a new cluster named OTV has been created and a spring bean has been distributed by using a cache object named user-map. It has been distributed between two members of the cluster.

Used Technologies :

JDK 1.6.0_21
Spring 3.0.5
Maven 3.0.2
Coherence 3.7.0
SolarisOS 5.10

STEP 1 : CREATE MAVEN PROJECT

A maven project is created as below. (It can be created by using Maven or IDE Plug-in).

STEP 2 : DOWNLOAD COHERENCE PACKAGE

Coherence package is downloaded via http://www.oracle.com/technetwork/middleware/coherence/downloads/index.html

STEP 3 : LIBRARIES

Firstly, Spring dependencies are added to Maven’ s pom.xml.

?
<!-- 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 library is installed to Local Maven Repository and its description is added to pom.xml as below. Also if maven is not used, coherence.jar file can be added to classpath.

?
<!-- Coherence library(from local repository) -->
<dependency>
    <groupId>com.tangosol</groupId>
    <artifactId>coherence</artifactId>
    <version>3.7.0</version>
</dependency>

For creating runnable-jar, below plugin can be used.

?
<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>

STEP 4 : CREATE otv-coherence-cache-config.xml

otv-coherence-cache-config.xml contains caching-schemes(distributed or replicated) and caching-scheme-mapping configuration. Created cache configuration should be added to 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>

STEP 5 : CREATE tangosol-coherence-override.xml

tangosol-coherence-override.xml contains cluster, member-identity and configurable-cache-factory configuration. Also below configuration xml file show first member of the cluster.

tangosol-coherence-override.xml for first member of the cluster :

?
<?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 for second member of the cluster :

?
<?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>

STEP 6 : CREATE applicationContext.xml

applicationContext.xml is created.

?
<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>

STEP 7 : CREATE SPRING BEAN

A new User Spring bean is created. This bean will be distributed between two node in OTV cluster. For serializing,java.io.Serializable interface has been implemented but PortableObject can be implemented for better performance.

?
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();
    }
}

STEP 8 : CREATE ICacheService INTERFACE

A new ICacheService Interface is created for service layer.

?
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);
     
}

STEP 9 : CREATE CacheService

CacheService is created for service layer by implementing 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);
        }
    }       
}

STEP 10 : CREATE USERMAPLISTENER IMPL CLASS

A new UserMapListener class is created. This listener receives distributed user-map events.

?
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());
    }   
}

STEP 11 : CREATE CacheUpdater

CacheUpdater Class is created to add new entry to cache and monitor cache content.

?
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();
        }
    }
}

STEP 12 : CREATE Application

Application Class is created to run the application.

?
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();
    }
}

STEP 13 : BUILD PROJECT

After OTV_Spring_Coherence Project is build, OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar will be created.
Important Note : Members of the cluster have got different configurations for Coherence so the project should be built separately for each member.

STEP 14 : RUN PROJECT ON FIRST MEMBER OF THE CLUSTER

After created OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar file is run at the members of the cluster, below output logs will be shown on first member’ s console:

?
--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

Second member’ s console :

?
--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

STEP 15 : DOWNLOAD

OTV_Spring_Coherence

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:

Published at DZone with permission of Eren Avşaroğulları, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}