Thursday, September 15, 2011

Using Ehcache in a distributed environment

In this blog I will show you how to use Ehcache to share data in a distributed environment. My suggestion is to start with a small app and get it running in a single node environment. Once the correct behavior of your app is verified, you can simply change Ehcache config to use RMI replicated caching and deploy your app to multiple nodes.

Lets start with a simple application in Java.

Class encapsulates the information we want cached. Notice this class needs to implement

package com.mycompany.myproject.mypackage;


public class Data implements Serializable {

private static final long serialVersionUID = 2725776132167576714L;
private String id;
private String name;

public Data(String id, String name) { = id; = name;

public Data(String name) { = name;

public String getId() {
return id;

public void setId(String id) { = id;

public String getName() {
return name;

public void setName(String name) { = name;

public int hashCode() {
int result = 0;
/* add code here */
return result;

public boolean equals(Object obj) {
/* add code here */
return true;

public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Data [id=");
builder.append(", name=");
return builder.toString();

You need to configure caching and let Ehcache handle your Data cache.

Ehcache works off of a configuration file in XML. By default if ehcache.xml is found on your classpath it will be used. Later on I will show you how to configure Ehcache without using "ehcache.xml".

For now, lets assume you are working with ehcache.xml. If you are using a Maven project, simply place this file in your src/main/resources.

ehcache.xml should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi=""
xsi:noNamespaceSchemaLocation="" updateCheck="false">

<diskStore path="" />

<defaultCache eternal="false" maxElementsInMemory="1000"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" statistics="true" />

<cache name="dataCache" eternal="true"
maxElementsInMemory="100" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" statistics="true" />


To initialize and start using the cached data, we need to create a class called DataCacheManager.

package com.mycompany.myproject.cache;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

public class DataCacheManager {

private String[] cacheNames;
private CacheManager cacheMgr;
private Cache dataCache;

public DataCacheManager() {
cacheMgr = CacheManager.create();
cacheNames = CacheManager.getInstance().getCacheNames();
dataCache = cacheMgr.getCache("dataCache");

public void getCache() {
dataCache = cacheMgr.getCache("dataCache");

public void addData(Data data) {
Element dataElement = new Element(data.getId(), data);

public Data getData(String id) {
Element dataElement = dataCache.get(id);
return (Data)dataElement.getValue();

public boolean deleteData(String id) {
return dataCache.remove(id);

public ArrayList getAllData() {
List keys = dataCache.getKeys();
Iterator iterator = keys.iterator();
ArrayList dataList = new ArrayList();
String key;
while (iterator.hasNext()) {
key = (String);
return dataList;

public Data addData(String id, String name) {
Data data = new Data(id, name);
return data;

public void deleteAllData() {

public String getUniqueDataId() {
UUID uuid = UUID.randomUUID();
return String.valueOf(uuid);

public static void main(String args[]) {
DataCacheManager dataCacheMgr = new DataCacheManager();
System.out.print("cacheNames = ");
for (int i = 0; i < dataCacheMgr.cacheNames.length; i++)
System.out.print(" " + dataCacheMgr.cacheNames[i]);
Data data = new Data("myUniqueId_123", "myName");
Data data2 = dataCacheMgr.getData("myUniqueId_123");

To run your application in a cluster of nodes and distribute it across multiple nodes, follow these steps:

Lets assume there are two nodes in your cluster.
1. Deploy your application to both nodes.
2. Modify your ehcache.xml as in the example below and place is on the classpath of each node.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi=""

<cacheManagerEventListenerFactory class="" properties="" />

<!-- Server 1 -->
properties="peerDiscovery=manual, rmiUrls=//" />

properties="hostName=, port=40001, socketTimeoutMillis=120000" />

<!-- Server 2 -->
properties="peerDiscovery=manual, rmiUrls=//" />

properties="hostName=, port=40001, socketTimeoutMillis=120000" />

<defaultCache eternal="true" maxElementsInMemory="100"
overflowToDisk="false" />

<cache name="dataCache" maxElementsInMemory="100"
eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,
replicateUpdatesViaCopy=false, replicateRemovals=true " />

<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />