在《Spring集成memcache(二)xmemcache》的基础之上扩展支持注解形式,使开发更加简洁。
参考资料如下:
http://zj0121.iteye.com/blog/1852270
需要注意的是扩展支持注解需要Spring AOP的支持,需要导入相应的jar包:
1.aopalliance-1.0.jar
2.aopalliance-alpha1.jar
3.slf4j-api-1.7.5.jar
其中slf4j-api-1.7.5.jar提供的是日志的接口规范,如果工程目录下使用的是log4j,则slf4j-api-1.7.5.jar会绑定调用log4j.jar。
具体说明可以访问http://blog.youkuaiyun.com/tengdazhang770960436/article/details/18006127。
从头开始进行配置,步骤如下:
1.添加xmemcache.jar包至工程中;
- aopalliance-1.0.jar
- aopalliance-alpha1.jar
- slf4j-api-1.7.5.jar
- xmemcached-1.3.8.jar
2.在web.xml文件中添加配置
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/conf/spring/*-beans.xml </param-value> </context-param>
3.在属性文件中添加如下配置:
#memcache配置
memcache.ip=127.0.0.1
memcache.port=11211
memcache.pool.size=5
4.在/WEB-INF/conf/spring/目录下添加配置文件memcache-beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd" default-autowire="byName"> <bean id="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder"> <constructor-arg> <list> <bean class="java.net.InetSocketAddress"> <constructor-arg value="${memcache.ip}" /> <constructor-arg value="${memcache.port}" /> </bean> </list> </constructor-arg> <property name="connectionPoolSize" value="${memcache.pool.size}" /> <property name="commandFactory"> <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory" /> </property> <property name="transcoder"> <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" /> </property> </bean> <bean id="memcachedClient" factory-bean="memcachedClientBuilder" factory-method="build" destroy-method="shutdown" /> <bean id="cacheManager" class="com.iaccount.framework.cache.memcache.MemcachedCacheManager"> <property name="memcachedClient" ref="memcachedClient" /> <property name="configMap"> <map> <!-- key:@Cacheable、@CachePut、@CacheEvict等的value属性。value:缓存过期时间(单位:秒),默认值:0 --> <entry key="defaultCache" value="0" /><!-- 默认缓存区 不过期 --> <entry key="inTimeCache" value="3600" /><!-- 实时缓存区 一小时过期 --> </map> </property> </bean> <cache:annotation-driven cache-manager="cacheManager" /> </beans>
5.参考了EHCacheCacheManager的源码,写了一个基于XMemcached的MemcachedCacheManager
a.memcache缓存连接类 MemCache.java
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.exception.MemcachedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MemCache {
private static Logger log = LoggerFactory.getLogger(MemCache.class);
private Set<String> keySet = new HashSet<String>();
private final String name;
private final int expire;
private final MemcachedClient memcachedClient;
public MemCache(String name, int expire, MemcachedClient memcachedClient) {
this.name = name;
this.expire = expire;
this.memcachedClient = memcachedClient;
}
public Object get(String key) {
Object value = null;
try {
key = this.getKey(key);
value = memcachedClient.get(key);
} catch (TimeoutException e) {
log.warn("获取 Memcached 缓存超时", e);
} catch (InterruptedException e) {
log.warn("获取 Memcached 缓存被中断", e);
} catch (MemcachedException e) {
log.warn("获取 Memcached 缓存错误", e);
}
return value;
}
public void put(String key, Object value) {
if (value == null)
return;
try{
key = this.getKey(key);
memcachedClient.setWithNoReply(key, expire, value);
keySet.add(key);
}catch (InterruptedException e){
log.warn("更新 Memcached 缓存被中断", e);
}catch (MemcachedException e){
log.warn("更新 Memcached 缓存错误", e);
}
}
public void clear(){
for (String key : keySet){
try{
memcachedClient.deleteWithNoReply(this.getKey(key));
}catch (InterruptedException e){
log.warn("删除 Memcached 缓存被中断", e);
}catch (MemcachedException e){
log.warn("删除 Memcached 缓存错误", e);
}
}
}
public void delete(String key){
try{
key = this.getKey(key);
memcachedClient.deleteWithNoReply(key);
}catch (InterruptedException e){
log.warn("删除 Memcached 缓存被中断", e);
}catch (MemcachedException e){
log.warn("删除 Memcached 缓存错误", e);
}
}
private String getKey(String key){
return name + "_" + key;
}
}
b.缓存类 MemcachedCache.java
import net.rubyeye.xmemcached.MemcachedClient;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
public class MemcachedCache implements Cache{
private final String name;
private final MemcachedClient memcachedClient;
private final MemCache memCache;
public MemcachedCache(String name, int expire, MemcachedClient memcachedClient){
this.name = name;
this.memcachedClient = memcachedClient;
this.memCache = new MemCache(name, expire, memcachedClient);
}
@Override
public void clear(){
memCache.clear();
}
@Override
public void evict(Object key){
memCache.delete(key.toString());
}
@Override
public ValueWrapper get(Object key){
ValueWrapper wrapper = null;
Object value = memCache.get(key.toString());
if (value != null){
wrapper = new SimpleValueWrapper(value);
}
return wrapper;
}
@Override
public String getName(){
return this.name;
}
@Override
public MemcachedClient getNativeCache(){
return this.memcachedClient;
}
@Override
public void put(Object key, Object value){
memCache.put(key.toString(), value);
}
}
c.缓存管理类 MemcachedCacheManager.java
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import net.rubyeye.xmemcached.MemcachedClient;
import org.springframework.cache.Cache;
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
public class MemcachedCacheManager extends AbstractTransactionSupportingCacheManager {
private ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
private Map<String, Integer> expireMap = new HashMap<String, Integer>();
private MemcachedClient memcachedClient;
public MemcachedCacheManager(){
}
@Override
protected Collection<? extends Cache> loadCaches(){
Collection<Cache> values = cacheMap.values();
return values;
}
@Override
public Cache getCache(String name){
Cache cache = cacheMap.get(name);
if (cache == null){
Integer expire = expireMap.get(name);
if (expire == null){
expire = 0;
expireMap.put(name, expire);
}
cache = new MemcachedCache(name, expire.intValue(), memcachedClient);
cacheMap.put(name, cache);
}
return cache;
}
public void setMemcachedClient(MemcachedClient memcachedClient){
this.memcachedClient = memcachedClient;
}
public void setConfigMap(Map<String, Integer> configMap){
this.expireMap = configMap;
}
}
6.数据操作类
@Cacheable(value="defaultCache")
public List<FmSupplier> getEnableSuppliers(){
FmSupplierQuery query = new FmSupplierQuery();
query.setIsDeleted(YesNoType.NO.getCode());
query.setSupplierStatus(SupplierStatus.ENABLE.getCode());
return fmSupplierMapper.selectListByQuery(query);
}
@Cacheable(value="defaultCache", key="#id")
public FmSupplier selectByPrimaryKey(Long id){
return fmSupplierMapper.selectByPrimaryKey(id);
}
1.在缓存区defaultCache中获取数据,第一次请求时无数据,则会从数据库中获取并放至缓存中;
2.第二次请求时则直接从缓存中获取;