Spring Cache与Tair结合
spring3.1.M1中的cache功能比较简便。可以与Tair结合,这样就不必每次缓存数据库结果集或者hsf结果的时候都写一段同样的代码。
spring3.1.M1中的cache主要使用两个注解标记。
@Cacheable:负责将方法的返回值加入到缓存中
@CacheEvict:负责清除缓存
@Cacheable 支持如下几个参数:
value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name
key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL
condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
@CacheEvict 支持如下几个参数:
value:缓存位置名称,不能为空,同上
key:缓存的key,默认为空,同上
condition:触发条件,只有满足条件的情况才会清除缓存,默认为空,支持SpEL
allEntries:true表示清除value中的全部缓存,默认为false
例子:
/** * TODO 如果没有注释,那么,你懂的 * * @author : mulou.zzy * Time: 下午3:51 */ @Component("dos") public class DoSomeThing { @Cacheable(value = "default", key="#a") public String doa(int a) { return (int)( Math.random()* 1000 )+ ""; } @Cacheable(value = "default",condition="#a > 50") public String dob(int a) { return (int)(Math.random()* 1000 )+ ""; } //清除掉全部缓存 @CacheEvict(value="default", key = "#a") public void delete(int a) { System.out.println("do delete when a = " + a); } }
实现结合Tair的Cache必须继承Spring的Cache接口
package com; /** * 一个简单的Tair Cache * * @author : mulou.zzy * Time: 下午3:31 */ public class TairCache implements Cache { Logger log = Logger.getLogger(Cache.class); @Resource private MultiClusterTairManager tairManager; private int nameSpace; public void setNameSpace(int nameSpace) { this.nameSpace = nameSpace; } private String name = "default"; @Override public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public MultiClusterTairManager getNativeCache() { return tairManager; } @Override public TairResult get(Object key) { Result<DataEntry> result = tairManager.get(nameSpace, (Serializable) key); if (result != null) { if (result.isSuccess() && result.getValue() != null) { TairResult tr = new TairResult(); tr.put((Serializable) result.getValue().getValue()); return tr; } else { log.warn(result.isSuccess() ? "value为空" : result.getRc().getMessage()); } } return null; } @Override public void put(Object key, Object value) { if (key != null || value != null) { if (key instanceof TairKey) { TairKey tairKey = (TairKey) key; this.isRcSuccess(this.tairManager.put(nameSpace, tairKey.getKey(), (Serializable) value, tairKey.getVersion(), tairKey.getTime())); } this.isRcSuccess(this.tairManager.put(nameSpace, (Serializable) key, (Serializable) value)); } } //清除缓存 @Override public void evict(Object key) { ResultCode rc = this.tairManager.delete(nameSpace, (Serializable) key); this.isRcSuccess(rc); } //tair返回是否成功 public boolean isRcSuccess(ResultCode rc) { if (rc != null) { if (rc.isSuccess()) { return true; } else { log.warn(rc.getMessage()); return false; } } log.warn("获取不到ResultCode"); return false; } //本来是清楚所有缓存方法,但是我们这里禁止掉。 @Override public void clear() { System.out.println("not allow to clear"); } }
因为@Cacheable标记中没有设置缓存时间和version的地方,所以我封装了一个TairKey类,存储Key和Version、time
但是这也不是一个好的解决方案, 目前我在用的是把key设置成String类型,在字符串末尾带上-version-time表示version和time
/** * TODO 如果没有注释,那么,你懂的 * * @author : mulou.zzy * Time: 上午11:34 */ public class TairKey implements Serializable { Serializable key; int time = 0; int version = 0; public int getTime() { return time; } public int getVersion() { return version; } public void setTime(int time) { this.time = time; } public void setVersion(int version) { this.version = version; } public Serializable getKey() { return key; } public void setKey(Serializable key) { this.key = key; } }
TairResult是封装了Tair返回的类
/** * TODO 如果没有注释,那么,你懂的 * * @author : mulou.zzy * Time: 下午3:41 */ public class TairResult<T extends Serializable> implements Cache.ValueWrapper { private T result; /** * Tair上的版本号 * */ private int version; /** * 存储时间,单位为秒 */ private int time; @Override public Object get() { return result; } public void put(T res){ this.result = res; } }
最后是配置的xml
<?xml version="1.0" encoding="GBK"?> <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" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://www.springframework.org/schema/p http://www.springframework.org/schema/p/spring-p.xsd" default-autowire="byName"> <cache:annotation-driven cache-manager="cacheManager"/> <context:annotation-config /> <context:component-scan base-package="com"/> <bean id="tairManager" class="com.taobao.tair.impl.mc.MultiClusterTairManager" init-method="init"> <property name="configID" value="ldbcommon-daily"/> <property name="dynamicConfig"> <value type="java.lang.Boolean">true</value> </property> </bean> <!-- generic cache manager --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="com.TairCache" p:name="default"/> </set> </property> </bean> </beans>
然后跑测试类
/** * TODO 如果没有注释,那么,你懂的 * * @author : mulou.zzy * Time: 下午3:08 */ public class Test { // org.springframework.cache.ehcache.EhCacheCacheManager ; // // // org.springframework.cache.support.SimpleCacheManager ; // ConcurrentCacheFactoryBean ; // ConcurrentMapCache //} public static void main(String s[]){ ApplicationContext ac = new ClassPathXmlApplicationContext("T.xml"); DoSomeThing dos = (DoSomeThing)ac.getBean("dos"); System.out.println(dos.doa(1111)); System.out.println(dos.doa(1111)); dos.delete(1111); System.out.println(dos.doa(1111)); System.out.println(dos.dob(1200)); System.out.println(dos.dob(1200)); dos.delete(1200); System.out.println(dos.dob(1200)); System.out.println(dos.dob(11)); System.out.println(dos.dob(11)); }
}