一。 首先,需要导入相关工具包,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; }
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); }
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); } }
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(); // } }
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."); } }