一。 首先,需要导入相关工具包,xmemcached-1.4.2.jar 为必须导入的工具包。
二。 进行具体工具类的编写工作,下面直接上代码。
CacheCallback.java
package cache;
import java.io.Serializable;
/**
* 缓存回调接口(供外部实现具体业务逻辑)
* 实现此接口提供缓存的key和被缓存的value的具体生产逻辑
* @author linwei
*
*/
public interface CacheCallback {
public String getKey();
public Serializable getValue() throws Exception;
}
CacheProvider.java
package cache;
/**
* 缓存的具体实现
* @author linwei
*
*/
public interface CacheProvider {
/**
* 获取缓存.
*
* @param key key
* @return 缓存的值
* @exception 如果获取缓存失败时,抛出此异常
*/
public CacheValue getCache(String key) throws Exception;
/**
* 添加缓存.
*
* @param key key
* @param value 缓存的值
*/
public void addCache(String key,CacheValue value);
/**
* 更新缓存.
*
* @param key key
* @param value 缓存的值
*/
public void updateCache(String key,CacheValue value);
/**
* 删除缓存.
*
* @param key key
*/
public void deleteCache(String key);
}
CacheTemplate.java
package cache;
import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 此类提供一种可以为任意方法提供缓存支持的机制.此类是线程安全的.
* @author linwei
*
*/
public class CacheTemplate {
private final static Logger logger = LoggerFactory.getLogger(CacheTemplate.class);
/**
* 默认的缓存过期时长:30分钟
*/
public final static int DEFAULT_EXPIRY = 30 * 60;
/**
* 默认的缓存过期时长,单位:秒
*/
private int expiry = DEFAULT_EXPIRY;
/**
* 在被缓存方法执行失败时,是否使用过期的缓存
*/
private boolean useOldCacheIfFail = true;
private ThreadPoolExecutor threadPool;
private CacheProvider cacheProvider;
public CacheTemplate(CacheProvider cacheProvider) {
this(cacheProvider, true);
}
public CacheTemplate(CacheProvider cacheProvider, boolean useOldCacheIfFail) {
this(cacheProvider, useOldCacheIfFail, DEFAULT_EXPIRY, initDefaultThreadPool());
}
public CacheTemplate(CacheProvider cacheProvider, boolean useOldCacheIfFail, int expiry, ThreadPoolExecutor threadPool) {
this.cacheProvider = cacheProvider;
this.expiry = expiry;
this.useOldCacheIfFail = useOldCacheIfFail;
this.threadPool = threadPool;
}
//设置初始默认线程池
private static ThreadPoolExecutor initDefaultThreadPool() {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20));
threadPool.allowCoreThreadTimeOut(true);
return threadPool;
}
/**
* 执行带有缓存的方法.
*
* @param callback
* CacheCallback接口实现
* @return 返回结果
* @throws Exception
* 执行带有缓存的方法失败时,抛出此异常
*/
public Object execute(CacheCallback callback) throws Exception {
return execute(callback, this.expiry);
}
/**
*
* @param callback
* CacheCallback接口实现
* @param expiry
* 缓存的过期时长,单位:秒
* @return 返回结果
* @throws Exception
* 执行带有缓存的方法失败时,抛出此异常
*/
public Object execute(CacheCallback callback, int expiry) throws Exception {
//从回调接口中获取key
String key = callback.getKey();
logger.debug("cache key:{}", key);
//如果key为空时,直接返回回调接口中的数值
if (null == key) {
Object value = callback.getValue();
logger.debug("key is null,directly return execution result value[{}]", value);
return value;
}
//从缓存服务中获取缓存
CacheValue cacheValue = null;
try {
cacheValue = this.cacheProvider.getCache(key);
logger.debug("fetch cache[key={},value={}]", key, cacheValue);
} catch (Exception e) {
Object value = callback.getValue();
logger.warn("failure to fetch key[" + key + "] cache,directly return execution result value[" + value + "].caused by:" + e.getLocalizedMessage(), e);
return value;
}
// 初始化缓存
if (null == cacheValue) {
Serializable initValue = callback.getValue();
logger.debug("initialized cache value:{}", initValue);
CacheValue initCacheValue = new CacheValue(initValue, new Date());
setCache(key, initCacheValue, false);
logger.debug("key[{}] cache is empty,return execution result value[{}] and added to cache[{}]", key, initValue, initCacheValue);
return initValue;
}
// 缓存过期
if (isExpired(cacheValue,expiry)) {
try {
Serializable newlValue = callback.getValue();
logger.debug("new cached value:{}", newlValue);
CacheValue newCacheValue = new CacheValue(newlValue, new Date());
setCache(key, newCacheValue, true);
logger.debug("key[{}] cache[{}] is expired,return re-execute result value[{}] and replaced by cache[{}]", key, cacheValue, newlValue, newCacheValue);
return newlValue;
} catch (Exception e) {
logger.warn("re-execute failed when key[" + key + "] cache[" + cacheValue + "] is expired,return old cache value[" + cacheValue.getObject() + "].caused by:" + e.getLocalizedMessage(), e);
if (!this.useOldCacheIfFail) {
throw e;
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("key[{}] cache[{}] is valid,return cached value[{}]", key, cacheValue, cacheValue.getObject());
}
}
return null;
}
/**
* 设置缓存
* @param key
* @param cacheValue
* @param isUpdated
*/
private void setCache(final String key, final CacheValue cacheValue, final boolean isUpdated) {
//采用线程池来执行操作
try {
this.threadPool.execute(new Runnable() {
@Override
public void run() {
try {
if (isUpdated) {
CacheTemplate.this.cacheProvider.updateCache(key, cacheValue);
} else {
CacheTemplate.this.cacheProvider.addCache(key, cacheValue);
}
} catch (Exception e) {
logger.warn("failure to set key[" + key + "] cache[" + cacheValue + "].caused by:" + e.getLocalizedMessage(), e);
}
}
});
} catch(RejectedExecutionException e){
logger.warn("failure to set key[" + key + "] cache[" + cacheValue + "].caused by:thread pool is full", e);
}
}
/**
* 删除缓存.
*
* @param key key
*/
public void deleteCache(String key){
this.cacheProvider.deleteCache(key);
}
public CacheValue getCache(String key) throws Exception {
return this.cacheProvider.getCache(key);
}
/**
* 判断缓存中的时间是否过期
* @param cacheValue
* @param expiry
* @return
*/
private boolean isExpired(CacheValue cacheValue,int expiry) {
Date currentDate=new Date();
Date expiredDate = DateUtils.addSeconds(cacheValue.getCreateDate(), expiry);
return currentDate.after(expiredDate);
}
}
CacheValue.java
package cache;
import java.io.Serializable;
import java.util.Date;
/**
* 保存到缓存中的实体.
* @author linwei
*
*/
public class CacheValue implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 缓存的内容
*/
private Serializable object;
/**
* 缓存的创建时间
*/
private Date createDate;
public CacheValue(Serializable object, Date createDate) {
this.object = object;
this.createDate = createDate;
}
public Serializable getObject() {
return this.object;
}
public void setObject(Serializable object) {
this.object = object;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((createDate == null) ? 0 : createDate.hashCode());
result = prime * result + ((object == null) ? 0 : object.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheValue other = (CacheValue) obj;
if (createDate == null) {
if (other.createDate != null)
return false;
} else if (!createDate.equals(other.createDate))
return false;
if (object == null) {
if (other.object != null)
return false;
} else if (!object.equals(other.object))
return false;
return true;
}
// @Override
// public String toString() {
// StringBuilder builder = new StringBuilder();
// builder.append("CacheValue [object=");
// builder.append(this.object);
// builder.append(", createDate=");
// builder.append(DateFormatUtils.format(this.createDate, "yyyy-MM-dd hh:mm:ss"));
// builder.append("]");
// return builder.toString();
// }
}
XMMemcCacheProvider.java
package cache;
import java.io.IOException;
import java.util.Arrays;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.utils.AddrUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 基于memcached的实现.使用的Client是Memcached-Java-Client.
* @author linwei
*
*/
public class XMMemcCacheProvider implements CacheProvider {
//内部静态类
public static class Config {
/**
* 服务地址
*/
private String servers;
/**
* 服务器负载量
*/
private int[] weights;
/**
* 操作超时,单位:毫秒
*/
private long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT;
/**
* 连接超时,单位:毫秒
*/
private int connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT;
public String getServers() {
return this.servers;
}
public void setServers(String servers) {
this.servers = servers;
}
public int[] getWeights() {
return this.weights;
}
public void setWeights(int... weights) {
this.weights = weights;
}
public long getOpTimeout() {
return this.opTimeout;
}
public void setOpTimeout(long opTimeout) {
this.opTimeout = opTimeout;
}
public int getConnectTimeout() {
return this.connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
private final static Logger logger = LoggerFactory.getLogger(XMMemcCacheProvider.class);
private MemcachedClient memcachedClient;
private int expiry = Integer.MAX_VALUE;
public XMMemcCacheProvider(Config config) {
logger.debug("loaded Config[{}]", config);
String[] servers = config.getServers().split(",");
int[] weights = config.getWeights();
if (ArrayUtils.isEmpty(weights)) {
weights = new int[servers.length];
Arrays.fill(weights, 1);
}
String serverList = formatServers(servers);
if (logger.isDebugEnabled()) {
logger.debug("servers:{}", serverList);
logger.debug("weights:{}", Arrays.toString(weights));
}
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(serverList), weights);
builder.setConnectTimeout(config.getConnectTimeout());
builder.setOpTimeout(config.getOpTimeout());
try {
this.memcachedClient = builder.build();
} catch (IOException e) {
throw new RuntimeException("failure to build MemcachedClient", e);
}
}
private String formatServers(String[] input) {
String[] array = new String[input.length];
for (int i = 0; i < array.length; i++) {
array[i] = input[i].trim();
}
return StringUtils.join(array, " ");
}
@Override
public CacheValue getCache(String key) throws Exception {
CacheValue value = (CacheValue) this.memcachedClient.get(key);
logger.debug("getted cache[{}] by key[{}]", value, key);
return value;
}
@Override
public void addCache(String key, CacheValue value) {
setCache(key, value);
logger.debug("added key[{}] cache[{}]", key, value);
}
@Override
public void updateCache(String key, CacheValue value) {
setCache(key, value);
logger.debug("updated key[{}] cache[{}]", key, value);
}
private void setCache(String key, CacheValue value) {
try {
this.memcachedClient.set(key, this.expiry, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void deleteCache(String key) {
try {
this.memcachedClient.delete(key);
logger.debug("deleted key[{}] cache", key);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
三。 进行测试。
CacheTest.java
package test;
import java.io.Serializable;
import java.util.Date;
import cache.CacheCallback;
import cache.CacheTemplate;
import cache.CacheValue;
import cache.XMMemcCacheProvider;
import cache.XMMemcCacheProvider.Config;
public class CacheTest {
private final static String servers = "127.0.0.1:11103";
public static void main(String[] args) throws Exception {
// addCache();
getCache();
}
private static void addCache() throws Exception {
Config config = new Config();
config.setServers(servers);
XMMemcCacheProvider xmMemcCacheProvider = new XMMemcCacheProvider(config);
CacheTemplate cacheTemplate = new CacheTemplate(xmMemcCacheProvider);
cacheTemplate.execute(new CacheCallback(){
@Override
public String getKey() {
return "alanlin";
}
@Override
public Serializable getValue() throws Exception {
return "testlin" + new Date();
}}
);
System.err.println("addCache over.");
}
private static void getCache() throws Exception {
Config config = new Config();
config.setServers(servers);
XMMemcCacheProvider xmMemcCacheProvider = new XMMemcCacheProvider(config);
CacheTemplate cacheTemplate = new CacheTemplate(xmMemcCacheProvider);
CacheValue cacheValue = cacheTemplate.getCache("alanlin");
System.err.println("value is " + cacheValue.getObject());
System.err.println("getCache over.");
}
}