使用MemCache进行相关缓存的保存处理

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








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值