设为首页 收藏本站
查看: 726|回复: 0

[经验分享] 使用MemCache进行相关缓存的保存处理

[复制链接]

尚未签到

发表于 2015-11-18 08:02:32 | 显示全部楼层 |阅读模式
  一。 首先,需要导入相关工具包,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(&quot;cache key:{}&quot;, key);
//如果key为空时,直接返回回调接口中的数值
if (null == key) {
Object value = callback.getValue();
logger.debug(&quot;key is null,directly return execution result value[{}]&quot;, value);
return value;
}
//从缓存服务中获取缓存
CacheValue cacheValue = null;
try {
cacheValue = this.cacheProvider.getCache(key);
logger.debug(&quot;fetch cache[key={},value={}]&quot;, key, cacheValue);
} catch (Exception e) {
Object value = callback.getValue();
logger.warn(&quot;failure to fetch key[&quot; + key + &quot;] cache,directly return execution result value[&quot; + value + &quot;].caused by:&quot; + e.getLocalizedMessage(), e);
return value;
}
// 初始化缓存
if (null == cacheValue) {
Serializable initValue = callback.getValue();
logger.debug(&quot;initialized cache value:{}&quot;, initValue);
CacheValue initCacheValue = new CacheValue(initValue, new Date());
setCache(key, initCacheValue, false);
logger.debug(&quot;key[{}] cache is empty,return execution result value[{}] and added to cache[{}]&quot;, key, initValue, initCacheValue);
return initValue;
}
// 缓存过期
if (isExpired(cacheValue,expiry)) {
try {
Serializable newlValue = callback.getValue();
logger.debug(&quot;new cached value:{}&quot;, newlValue);
CacheValue newCacheValue = new CacheValue(newlValue, new Date());
setCache(key, newCacheValue, true);
logger.debug(&quot;key[{}] cache[{}] is expired,return re-execute result value[{}] and replaced by cache[{}]&quot;, key, cacheValue, newlValue, newCacheValue);
return newlValue;
} catch (Exception e) {
logger.warn(&quot;re-execute failed when key[&quot; + key + &quot;] cache[&quot; + cacheValue + &quot;] is expired,return old cache value[&quot; + cacheValue.getObject() + &quot;].caused by:&quot; + e.getLocalizedMessage(), e);
if (!this.useOldCacheIfFail) {
throw e;
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug(&quot;key[{}] cache[{}] is valid,return cached value[{}]&quot;, 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(&quot;failure to set key[&quot; + key + &quot;] cache[&quot; + cacheValue + &quot;].caused by:&quot; + e.getLocalizedMessage(), e);
}
}
});
} catch(RejectedExecutionException e){
logger.warn(&quot;failure to set key[&quot; + key + &quot;] cache[&quot; + cacheValue + &quot;].caused by:thread pool is full&quot;, 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(&quot;CacheValue [object=&quot;);
//builder.append(this.object);
//builder.append(&quot;, createDate=&quot;);
//builder.append(DateFormatUtils.format(this.createDate, &quot;yyyy-MM-dd hh:mm:ss&quot;));
//builder.append(&quot;]&quot;);
//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(&quot;loaded Config[{}]&quot;, config);
String[] servers = config.getServers().split(&quot;,&quot;);
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(&quot;servers:{}&quot;, serverList);
logger.debug(&quot;weights:{}&quot;, 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(&quot;failure to build MemcachedClient&quot;, e);
}
}
private String formatServers(String[] input) {
String[] array = new String[input.length];
for (int i = 0; i < array.length; i++) {
array = input.trim();
}
return StringUtils.join(array, &quot; &quot;);
}
@Override
public CacheValue getCache(String key) throws Exception {
CacheValue value = (CacheValue) this.memcachedClient.get(key);
logger.debug(&quot;getted cache[{}] by key[{}]&quot;, value, key);
return value;
}
@Override
public void addCache(String key, CacheValue value) {
setCache(key, value);
logger.debug(&quot;added key[{}] cache[{}]&quot;, key, value);
}
@Override
public void updateCache(String key, CacheValue value) {
setCache(key, value);
logger.debug(&quot;updated key[{}] cache[{}]&quot;, 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(&quot;deleted key[{}] cache&quot;, 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 = &quot;127.0.0.1:11103&quot;;
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 &quot;alanlin&quot;;
}
@Override
public Serializable getValue() throws Exception {
return &quot;testlin&quot; + new Date();
}}
);
System.err.println(&quot;addCache over.&quot;);
}
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(&quot;alanlin&quot;);
System.err.println(&quot;value is &quot; + cacheValue.getObject());
System.err.println(&quot;getCache over.&quot;);
}
}


   
  


  


  


  


  


  


  



版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-140470-1-1.html 上篇帖子: Memcache遍历 获取模糊匹配key对应的记录 下篇帖子: memcache还是redis
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表