cache策略(五)memcached

cache策略(五)memcached

下载client的jar包
http://www.whalin.com/memcached/

得到jar包,同时导入maven私服
pom.xml如下:
<dependency>
<groupId>com.danga</groupId>
<artifactId>memcached</artifactId>
<version>2.0.1</version>
</dependency>

memcached主要参考了北京一个同事的实现方法,同时为了适应总体的cache接口,做了些调整
MemCache.java如下:
package com.sillycat.easyview.plugin.cache.memcached;

import java.util.Calendar;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.danga.MemCached.MemCachedClient;
import com.sillycat.easyview.plugin.cache.CacheManager;
import com.sillycat.easyview.plugin.cache.base.Cache;
import com.sillycat.easyview.plugin.cache.base.Timestamper;
import com.sillycat.easyview.plugin.commons.exceptions.CacheException;

public class MemCache implements Cache {

private static final Log log = LogFactory.getLog(MemCache.class);

private static final int SIXTY_THOUSAND_MS = 60000; // 1分钟的,或称1分钟包含的毫秒值

private MemCachedClient mc;
private String regionName; // 缓存区域标识
private int expireTimeInSecond;// 该存储区域对缓存对象过期时间值
private String keyPrefix; // 通过对象的key前缀区别不同缓存区域的对象

public MemCache(String poolName, String regionName,
    int expireTimeInSecond, Boolean compressEnable,
    Integer compressThreshold) {
   mc = new MemCachedClient(poolName);
   if (compressEnable != null) {
    mc.setCompressEnable(compressEnable.booleanValue());
   }
   if (compressThreshold != null) {
    mc.setCompressThreshold(compressThreshold.intValue());
   }
   this.expireTimeInSecond = expireTimeInSecond;
   this.regionName = regionName;
   this.keyPrefix = regionName + '-';
}

private String rebuildKey(Object key) {
   return keyPrefix + key.toString().hashCode();
}

public Object get(Object key) throws CacheException {
   if (log.isDebugEnabled()) {
    log.debug("get Element by key: " + key);
   }
   if (key == null) {
    return null;
   } else {
    Object rt = mc.get(rebuildKey(key));
    if (rt == null) {
     if (log.isDebugEnabled()) {
      log.debug("Element for " + key + " is null");
     }
     return null;
    } else {
     if (log.isDebugEnabled()) {
      log.debug("Got an element by " + key);
     }
     return rt;
    }
   }

}

public Object read(Object key) throws CacheException {
   return get(rebuildKey(key));
}

public void update(Object key, Object value) throws CacheException {
   if (expireTimeInSecond <= 0)
    mc.replace(rebuildKey(key), value);
   else {
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.SECOND, expireTimeInSecond);
    mc.replace(rebuildKey(key), value, cal.getTime());
   }
}

public void put(Object key, Object value) throws CacheException {
   if (expireTimeInSecond <= 0)
    mc.set(rebuildKey(key), value);
   else {
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.SECOND, expireTimeInSecond);
    mc.set(rebuildKey(key), value, cal.getTime());
   }
}

public void remove(Object key) throws CacheException {
   mc.delete(rebuildKey(key));
}

public void clear() throws CacheException {
   mc.flushAll();
}

public void destroy() throws CacheException {

}

public void lock(Object key) throws CacheException {
}

public void unlock(Object key) throws CacheException {
}

public long nextTimestamp() {
   return Timestamper.next();
}
public int getTimeout() {
   // 60 second lock timeout
   return Timestamper.ONE_MS * SIXTY_THOUSAND_MS;
}

public String getRegionName() {
   return regionName;
}


public String toString() {
   return "MemCached(" + getRegionName() + ')';
}

public long getElementCountInMemory() {
   return 0;
}

public long getElementCountOnDisk() {
   return 0;
}

public long getSizeInMemory() {
   return 0;
}

public Map toMap() {
   return null;
}
}

MemCacheProvider.java 如下:
package com.sillycat.easyview.plugin.cache.memcached;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.danga.MemCached.SockIOPool;
import com.sillycat.easyview.plugin.cache.base.Cache;
import com.sillycat.easyview.plugin.cache.base.CacheProvider;
import com.sillycat.easyview.plugin.commons.exceptions.CacheException;
import com.sillycat.easyview.plugin.commons.utils.PropertiesUtil;
import com.sillycat.easyview.plugin.commons.utils.StringUtil;

public class MemCacheProvider implements CacheProvider {

private static final Log log = LogFactory.getLog(MemCacheProvider.class);

public final static String DEFAULT_REGION_NAME = "default";

public static final int DEFAULT_EXPIRE_TIME_IN_SEC = 10 * 60;

private Hashtable<String, MemCache> caches;

public Properties getProperties() throws CacheException {
   Properties props = new Properties();
   String properties = props.getProperty("memcached.conf",
     "memcached.properties");
   props.setProperty("memcached.conf", properties);
   Resource propertiesResource = new ClassPathResource(properties);
   try {
    if (!propertiesResource.exists()) {
     throw new CacheException("not found '" + properties
       + "' in classpath!");
    }
    InputStream propertiesInputStream = propertiesResource
      .getInputStream();
    props.load(propertiesInputStream);
    propertiesInputStream.close();
    // 如果没有设置poolName,则以属性文件地址名自动设置之
    if (props.getProperty("memcached.poolName") == null) {
     props.setProperty("memcached.poolName", properties.substring(0,
       properties.lastIndexOf('.')));
    }

    log.info("Loaded '" + properties + "' from "
      + propertiesResource.getFile().getAbsolutePath());
   } catch (Exception e) {
    throw new CacheException("fail to load/read '" + properties + "'",
      e);
   }
   return props;
}

public void start() throws CacheException {
   Properties props = this.getProperties();
 
   caches = new Hashtable<String, MemCache>();
   //
   SockIOPool pool = SockIOPool.getInstance(props
     .getProperty("memcached.poolName"));
   if (pool.isInitialized()) {
    log.info("MemcachedCacheProvider.SockIOPool has been Started!");
   } else {
    String servers = props.getProperty("memcached.servers");
    if (StringUtil.isBlank(servers)) {
     throw new CacheException(
       "configuration 'servers' get a empty value");
    }
    pool.setServers(servers.split(","));
    //
    String weights = props.getProperty("weights");
    if (weights != null) {
     String[] ws = weights.split(",");
     Integer[] iws = new Integer[ws.length];
     for (int i = 0; i < iws.length; i++) {
      iws[i] = Integer.parseInt(ws[i]);
     }
     pool.setWeights(iws);
    }
    //
    pool.setFailover(PropertiesUtil.getBoolean(props,
      "memcached.failover"));
    pool.setFailback(PropertiesUtil.getBoolean(props,
      "memcached.failback"));
    pool
      .setInitConn(PropertiesUtil.getInt(props,
        "memcached.initConn"));
    pool.setMinConn(PropertiesUtil.getInt(props, "memcached.minConn"));
    pool.setMaxConn(PropertiesUtil.getInt(props, "memcached.maxConn"));
    pool.setMaintSleep(PropertiesUtil.getInt(props,
      "memcached.maintSleep"));
    pool.setNagle(PropertiesUtil.getBoolean(props, "memcached.nagle"));
    pool
      .setSocketTO(PropertiesUtil.getInt(props,
        "memcached.socketTO"));
    pool.setAliveCheck(PropertiesUtil.getBoolean(props,
      "memcached.aliveCheck"));
    pool.initialize();
   }

   log.info("MemcachedCacheProvider Started!");
}

private static int getSeconds(String str) {
   try {
    switch (str.charAt(str.length() - 1)) {
    case 's':
     return Integer.parseInt(str.substring(0, str.length() - 1));
    case 'm':
     return Integer.parseInt(str.substring(0, str.length() - 1)) * 60;
    case 'h':
     return Integer.parseInt(str.substring(0, str.length() - 1)) * 3600;
    case 'd':
     return Integer.parseInt(str.substring(0, str.length() - 1)) * 86400;
    default:
     return Integer.parseInt(str);
    }
   } catch (NumberFormatException e) {
    log.warn("Illegal configuration value : " + str, e);
   }
   return -1;
}

public Cache buildCache(String regionName) throws CacheException {
   if (caches == null) {
    throw new IllegalStateException("Please start the provider first!");
   }
   Properties props = this.getProperties();
   String poolName = props.getProperty("memcached.poolName");
   if (StringUtil.isBlank(regionName)) {
    regionName = DEFAULT_REGION_NAME;
   }
   MemCache mCache = caches.get(regionName);
   if (mCache == null) {
    String expireTimeExpression = props.getProperty("memcached.region."
      + regionName + ".expireTime");
    if (StringUtil.isBlank(expireTimeExpression)) {
     expireTimeExpression = props
       .getProperty("memcached.expireTime");
    }
    int expireTimeInSecond = -1;
    if (StringUtil.isNotBlank(expireTimeExpression)) {
     expireTimeExpression = expireTimeExpression.toLowerCase()
       .trim();
     expireTimeInSecond = getSeconds(expireTimeExpression);
    } else {
     expireTimeInSecond = DEFAULT_EXPIRE_TIME_IN_SEC;
    }
    //
    String pcompressEnable = props.getProperty("memcached.region."
      + regionName + ".compressEnable");
    if (pcompressEnable == null) {
     pcompressEnable = props.getProperty("memcached.compressEnable");
    }
    Boolean compressEnable = null;
    if (pcompressEnable != null) {
     compressEnable = Boolean.parseBoolean(pcompressEnable);
    }
    //

    String pcompressThreshold = props.getProperty("memcached.region."
      + regionName + ".compressThreshold");
    if (pcompressThreshold == null) {
     pcompressThreshold = props
       .getProperty("memcached.compressThreshold");
    }
    Integer compressThreshold = null;
    if (compressThreshold != null) {
     compressThreshold = Integer.parseInt(pcompressThreshold);
    }
    log.info("Building cache named " + regionName
      + " using expireTimeInSecond is " + expireTimeInSecond);
    mCache = new MemCache(poolName, regionName, expireTimeInSecond,
      compressEnable, compressThreshold);
    caches.put(regionName, mCache);
   }
   return mCache;
}

public long nextTimestamp() {
   return 0;
}

public void stop() {

}

}

memcached.properties配置文件,配置文件主要参考了北京同事的写法,学到了不少东东:

############################################################
## list of cache server, e.g: "memcached-1.nms:11211,memcached-2.nms:11211"
## memcached1.nms & memcached2.nms are host names here, they should be configuired in /etc/hosts
memcached.servers=192.168.10.253:11211

## Sets the list of weights to apply to the server list.
## This is an int array with each element corresponding to an element
## in the same position in the server String array.
#memcached.weights=

############################################################
## Sets the failover flag for the pool.
## If this flag is set to true, and a socket fails to connect,
## the pool will attempt to return a socket from another server if one exists.
## If set to false, then getting a socket will return null if it fails to connect to the requested server.
memcached.failover=true

## Sets the failback flag for the pool.
## If this is true and we have marked a host as dead,
## will try to bring it back. If it is false, we will never
## try to resurrect a dead host.
memcached.failback=true

############################################################
## Sets the initial number of connections per server in the available pool.
memcached.initConn=1

## Sets the minimum number of spare connections to maintain in our available pool.
memcached.minConn=1

## Sets the maximum number of spare connections allowed in our available pool.
memcached.maxConn=10

## maintenance thread sleep time
memcached.maintSleep=30000

## default timeout of socket reads
memcached.socketTO=30000

## default to not check each connection for being alive
memcached.aliveCheck=false

## enable/disable Nagle's algorithm
memcached.nagle=true

## Enable storing compressed data, provided it meets the threshold requirements.
## If enabled, data will be stored in compressed form if it is
## longer than the threshold length set with setCompressThreshold(int)
## The default is that compression is enabled.
## Even if compression is disabled, compressed data will be automatically decompressed.
memcached.compressEnable=true
#memcached.region.[regionName].compressEnable to spec for the named cache

## Sets the required length for data to be considered for compression.
## If the length of the data to be stored is not equal or larger than this value, it will
## not be compressed.
## This defaults to 15 KB(30720).
memcached.compressThreshold=30720
#memcached.region.[regionName].compressThreshold to spec for the named cache

##
memcached.expireTime=3m
#memcached.region.[regionName].memcached.expireTime to spec for the named cache

###################################################
## region cacha conf followed:

你可能感兴趣的:(apache,maven,cache,socket,memcached)