Store 类来实现自己Memcached、Tokyo Tyrant、Redis等Key-Value DB的客户端。
以Memcached的客户端为例(摘自Use MemCacheStore in Tomcat):
package com.yeeach;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
public class MemCacheStore extends StoreBase implements Store {
/**
* The descriptive information about this implementation.
*/
protected static String info = "MemCacheStore/1.0";
/**
* The thread safe and thread local memcacheclient instance.
*/
private static final ThreadLocal<MemCachedClient> memclient = new ThreadLocal<MemCachedClient>();
/**
* The server list for memcache connections.
*/
private List<String> servers = new ArrayList<String>();
/**
* all keys for current request session.
*/
private List<String> keys = Collections
.synchronizedList(new ArrayList<String>());
/**
* Return the info for this Store.
*/
public String getInfo() {
return (info);
}
/**
* Clear all sessions from the cache.
*/
public void clear() throws IOException {
getMemcacheClient().flushAll();
keys.clear();
}
/**
* Return local keyList size.
*/
public int getSize() throws IOException {
return getKeyList().size();
}
/**
* Return all keys
*/
public String[] keys() throws IOException {
return getKeyList().toArray(new String[] {});
}
/**
* Load the Session from the cache with given sessionId.
*
*/
public Session load(String sessionId) throws ClassNotFoundException,
IOException {
/**
* transform a vaild Session from objectinputstream.
* Check which classLoader is responsible for the current instance.
*
* @param bytes
* @return ObjectInputStream with the Session object.
* @throws IOException
*/
private ObjectInputStream bytesToObjectStream(byte[] bytes)
throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = null;
Loader loader = null;
ClassLoader classLoader = null;
Container container = manager.getContainer();
if (container != null)
loader = container.getLoader();
if (loader != null)
classLoader = loader.getClassLoader();
if (classLoader != null)
ois = new CustomObjectInputStream(bais, classLoader);
else
ois = new ObjectInputStream(bais);
return ois;
}
/**
* remove the session with given sessionId
*/
public void remove(String sessionId) throws IOException {
getMemcacheClient().delete(sessionId);
List<String> keyList = getKeyList();
keyList.remove(sessionId);
}
/**
* Store a objectstream from the session into the cache.
*/
public void save(Session session) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
StandardSession standard = (StandardSession) session;
standard.writeObjectData(oos);
getMemcacheClient().add(session.getId(), baos.toByteArray());
Object ob = getMemcacheClient().get(session.getId());
List<String> keyList = getKeyList();
keyList.add(session.getId());
}
/**
* Simple instanc of the Memcache client and SockIOPool.
* @return memchacheclient
*/
private MemCachedClient getMemcacheClient() {
if (memclient == null) {
Integer[] weights = { 1 };
// grab an instance of our connection pool
SockIOPool pool = SockIOPool.getInstance();
if (!pool.isInitialized()) {
String[] serverlist = servers.toArray(new String[] {});
// set the servers and the weights
pool.setServers(serverlist);
pool.setWeights(weights);
// set some basic pool settings
// 5 initial, 5 min, and 250 max conns
// and set the max idle time for a conn
// to 6 hours
pool.setInitConn(5);
pool.setMinConn(5);
pool.setMaxConn(250);
pool.setMaxIdle(1000 * 60 * 60 * 6);
// set the sleep for the maint thread
// it will wake up every x seconds and
// maintain the pool size
pool.setMaintSleep(30);
// set some TCP settings
// disable nagle
// set the read timeout to 3 secs
// and don't set a connect timeout
pool.setNagle(false);
pool.setSocketTO(3000);
pool.setSocketConnectTO(0);
// initialize the connection pool
pool.initialize();
}
// lets set some compression on for the client
// compress anything larger than 64k
public List<String> getServers() {
return servers;
}
public void setServers(String serverList) {
StringTokenizer st = new StringTokenizer(serverList, ", ");
servers.clear();
while (st.hasMoreTokens()) {
servers.add(st.nextToken());
}
}
The memcached session manager installed in a tomcat holds all sessions locally in the own jvm, just like the StandardManager does it as well.
Additionally, after a request was finished, the session (only if existing) is additionally sent to a memcached node for backup.
When the next request for this session has to be served, the session is locally available and can be used, after this second request is finished the session is updated in the memcached node.