spring3.1之后引进了cache,我们可以使用CacheManager、Cache以及相关缓存注解将缓存集成到系统中,但spring并没有提供配置缓存超时的机制,笔者结合spring的 aspect实现了相关的超时设置功能
缓存配置文件:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
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.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="com.project.core.cache.SpringCacheManager">
<property name="caches">
<set>
<bean class="com.project.core.cache.memcached.Memcache">
<property name="name" value="memcache"/>
<property name="memCachedClient">
<bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
</bean>
</property>
</bean>
</set>
</property>
</bean>
<bean id="sockIOPool" class="com.danga.MemCached.SockIOPool"
factory-method="getInstance" init-method="initialize" destroy-method="shutDown" lazy-init="false">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
<property name="servers">
<list>
<value>127.0.0.1:11211</value>
</list>
</property>
<property name="initConn">
<value>5</value>
</property>
<property name="maxConn">
<value>100</value>
</property>
<property name="maintSleep">
<value>30</value>
</property>
<property name="nagle">
<value>false</value>
</property>
<property name="socketTO">
<value>3000</value>
</property>
</bean>
</beans>
SpringCacheManager.java
package com.project.core.cache;
import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
import java.util.Collection;
public class SpringCacheManager extends AbstractCacheManager {
private Collection<? extends Cache> caches;
@Override
protected Collection<? extends Cache> loadCaches() {
return caches;
}
public void setCaches(Collection<? extends Cache> caches) {
this.caches = caches;
}
}
package com.project.core.cache.memcached;
import com.danga.MemCached.MemCachedClient;
import com.project.core.cache.CacheContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import java.util.Collection;
import java.util.Date;
public class Memcache implements Cache {
protected final Logger logger = LoggerFactory.getLogger(Memcache.class);
private String name;
private MemCachedClient memCachedClient;
public Memcache() {
}
public Memcache(String name) {
this.name = name;
}
public void setMemCachedClient(MemCachedClient memCachedClient) {
this.memCachedClient = memCachedClient;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getNativeCache() {
return memCachedClient;
}
public ValueWrapper get(Object key) {
System.out.println("memcache get:"+key);
logger.info("读取memcached,key=" + key);
if( key==null ){
return null;
}
try {
Object value = memCachedClient.get(key.toString());
if (value != null) {
return new SimpleValueWrapper(value);
}
} catch (Exception e) {
logger.error("读取memcached失败,key=" + key, e);
}
return null;
}
public void put(Object key, Object value) {
System.out.println("memcache put:"+key);
logger.info("写memcached,key=" + key);
try {
if (key==null||value == null) {
return;
}
Long overtime = CacheContext.getOverTime();//从上下文中获取超时时间
if( overtime!=null ){
memCachedClient.set(key.toString(),value,
new Date(System.currentTimeMillis()+ overtime));
}else{
memCachedClient.set(key.toString(), value);
}
} catch (Exception e) {
logger.error("写memcached缓存失败,key=" + key, e);
}finally{
//CacheContext.removeOverTime();
}
}
@SuppressWarnings("rawtypes")
public void evict(Object key) {
logger.info("删除memcached缓存,key=" + key);
try {
if(key==null){
return;
}
if (key.getClass().isArray()) {
for (Object k : (Object[]) key) {
memCachedClient.delete((k == null ? "" : k.toString()));
}
} else if (key instanceof Collection) {
for (Object k : (Collection) key) {
memCachedClient.delete((k == null ? "" : k.toString()));
}
} else {
memCachedClient.delete(key.toString());
}
} catch (Exception e) {
logger.error("删除memcached缓存失败,key=" + key, e);
}
}
public void clear() {
logger.info("memcached flush all!");
memCachedClient.flushAll();
}
public <T> T get(Object key, Class<T> type) {
return null;
}
public ValueWrapper putIfAbsent(Object key, Object value) {
return null;
}
}
package com.myproject.user.dao;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import com.myproject.support.dao.BaseDao;
import com.myproject.user.model.User;
import com.project.core.cache.annotation.Overtime;
@Repository
@CacheConfig(cacheNames="memcache")
public class UserDao extends BaseDao {
@Cacheable(key = "'USER_'+#user.id")
@Overtime(1000000L)
public User queryForObjectById(User user){
user = getSqlSession().selectOne(getNamespace()+"queryById", user);
return user;
}
}
CacheContext.java
package com.project.core.cache;
public abstract class CacheContext {
private final static ThreadLocal<Long> overTime = new ThreadLocal<Long>();
public static void setOverTime(Long time){
overTime.set(time);
}
public static Long getOverTime(){
return overTime.get();
}
public static void removeOverTime(){
overTime.remove();
}
}
Overtime.java
package com.project.core.cache.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Overtime {
long value() default 0;
}
CacheOverTimeAspect.java
package com.project.core.cache;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.project.core.cache.annotation.Overtime;
@Component
@Aspect
public class CacheOverTimeAspect {
@Before("@annotation(com.project.core.cache.annotation.Overtime)")
public void before(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Overtime overTime = method.getAnnotation(Overtime.class);
if( overTime!=null&&overTime.value()>0 ){
CacheContext.setOverTime(overTime.value());//在上下文中设置超时时间
}
}
@After("@annotation(com.project.core.cache.annotation.Overtime)")
public void after( JoinPoint joinPoint ){
CacheContext.removeOverTime();//清除上下文超时时间
}
}