从Spring3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring-context包提供了@Cacheable,@CachePut , @CacheEvict,@CacheConfig,@EnableCaching,@Caching等注解,接下来就一一攻破!
@Cacheable注解
先点进去看看源码吧
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
/**
* 缓存位置名称,不能为空
*/
@AliasFor("cacheNames")
String[] value() default {};
/**
* 存储方法调用结果的缓存的名称。名称可用于确定目标缓存(或多个缓存),匹配特定bean定义的限定符值或bean名称。
*/
@AliasFor("value")
String[] cacheNames() default {};
/**
* 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
*
*/
String key() default "";
/**
* 自定义key生成策略
*/
String keyGenerator() default "";
/**
* 自定义cacheManager
* 与{@link #cacheResolver}属性互斥。
*/
String cacheManager() default "";
/**
* 自定义cacheResolver
*/
String cacheResolver() default "";
/**
* 触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
*/
String condition() default "";
/**
* 否决缓存条件,支持SpEL
*/
String unless() default "";
/**
* 是否支持同步
*/
boolean sync() default false;
}
哇!属性还是挺多的,而我们最常用的还是value,key,condition,Spring自带了KeyGenerator()--key生成策略
public SimpleKey(Object... elements) {
Assert.notNull(elements, "Elements must not be null");
this.params = new Object[elements.length];
System.arraycopy(elements, 0, this.params, 0, elements.length);
this.hashCode = Arrays.deepHashCode(this.params);
}
这就是key的默认生成策略:
- 如果方法没有参数,则使用0作为key。
- 如果只有一个参数的话则使用该参数作为key。
- 如果参数多余一个的话则使用所有参数的hashCode作为key。
当然也可以自己实现KeyGenerator;
@Component
public class CacheKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(target.getClass().getCanonicalName());
stringBuilder.append(":");
stringBuilder.append(method.getName());
stringBuilder.append(":");
for (int i = 0; i < params.length; i++) {
stringBuilder.append(params[i]);
if (i < params.length - 1) {
stringBuilder.append(",");
}
}
return stringBuilder.toString();
}
我的就比较简单了,将所有的入参全拼到key中,笔者觉得默认的key生成比较繁琐,且key值可读性也比较查,到不如在key()属性中定义来的简洁明了,上述中多次提到SpEL表达式,到底是何方神圣呢?
SpEL(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言;是一种可以与一个基于spring的应用程序中的运行时对象交互的东西;是一种简化开发的表达式,通过使用表达式来简化开发,减少一些逻辑、配置的编写。
这里只贴出key解析的部分代码,想了解更多SpEL表达式可以参考SpEL--Spring表达式语言。
private String parseKey(String key, String fileKey, Method method,Object[] args){
if (StringUtils.isEmpty(fileKey)) {
return key;
}
//获得被拦截方法参数列表
LocalVariableTableParameterNameDiscoverer nd = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = nd.getParameterNames(method);
Expression expression = parser.parseExpression(fileKey);
EvaluationContext context = new StandardEvaluationContext();
for(int i = 0 ; i < args.length ; i++) {
context.setVariable(parameterNames[i], args[i]);
}
return key+":"+expression.getValue(context).toString();
}
解释完了,用起来就简单了
@Cacheable(value = "names", key = "#id",condition = "id>0",unless = "id<0",keyGenerator = "cacheKeyGenerator")
@CachePut
用法与@Cacheable相同,区别在于每次调用都会触发更新缓存。
@CacheEvict
作用是缓存清除,这里贴出@CacheEvict独有属性
/**
* 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
*/
boolean allEntries() default false;
/**
是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
*/
boolean beforeInvocation() default false;
@CacheConfig
声明于类上,只要抽象类中方法上@Cacheable的共性,说明白点:所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了,@CacheConfig就干这事。
@Caching
有时候我们可能组合多个Cache注解使用;看来代码你就明白了。
@Caching(put = {
@CachePut(value = "names",key = "#name"),
@CachePut(value = "names",key = "#id")
},cacheable = {
@Cacheable(value = "names",key = "#name"),
@Cacheable(value = "names",key = "#id")
})
当然如果这些注解还满足你的需求,你还可以自定义注解,之前便在项目中用了:
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisCache {
//redis分组
String key() default "lianhua";
//key支持spel表达式
String filekey() default "";
//返回类型
Class type();
//是否刷新
boolean reSet() default false;
//默认缓存时间是一天
long expire() default 60*60*24L;
}
最后附上码云上的小demo,欢迎star。
网友评论