Spring cache缓存注解
Spring提供注解来支持Spring cache。Spring cache是作用在方法上的,当调用一个缓存方法时,会把该方法的参数和结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时,就不再执行该方法,而是从缓存直接返回。
一、@Cacheable
@Cacheable可以标记在一个类上,也可以标记在一个方法上。标记在一个类上,则表明该类的所有方法都是支持缓存的。Spring在缓存方法的返回值都是以键值对进行缓存的,值就是方法的返回结果,至于key的话,Spring支持两种策略,默认策略和自定义策略。
注意:当一个支持缓存的方法在对象内部被调用是不会触发缓存功能的。
@Cacheable可以指定三个属性,value、key和condition
1.1 value属性
value属性指定cache名称,表示当前方法是会被缓存在哪个cache上,对应cache的名称。其可以是一个cache也可以是多个cache,当需要指定多个cache时是一个数组。
@Cacheable(value = "getConfCustomer",unless="#result == null") // Cache是发生在getConfCustomer上的
public ConfCustomerInfoVo getConfCustomer(String confCustomerCodes,String lotNo){
}
@Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
public User find(Integer id) {
returnnull;
}
1.2 key属性
key属性是用来指定缓存方法返回结果对应的key的。该属性支持SpringEL表达式。当没有指定key时,将使用默认策略生成key。
1.2.1 自定义策略
自定义策略是指我们可以通过SpringEL表达式来指定key。EL表达式可以使用方法参数及他们对应的属性,使用方法参数时,可以直接使用“#参数名”或者“#p参数index”,如下所示:
第一种:
@Cacheable(value = "getConfCustomer",key="#confCustomerCodes",unless="#result == null")
public ConfCustomerInfoVo getConfCustomer(String confCustomerCodes){
}
第二种:
@Cacheable(value = "getConfCustomer",key="#p0",unless="#result == null")
public ConfCustomerInfoVo getConfCustomer(String confCustomerCodes){
}
第三种:当参数是一个对象时
@Cacheable(value="users", key="#user.id")
public User find(User user) {
returnnull;
}
@Cacheable(value="users", key="#p0.id")
public User find(User user) {
returnnull;
}
除了可以使用上述方法作为key之外,Spring还提供了一个root对象可以用来生成key。使用方式如下:
属性名称 | 描述 | 示例 |
---|---|---|
methodName | 当前方法名 | #root.methodName |
method | 当前方法 | #root.method.name |
target | 当前被调用的对象 | #root.target |
targetClass | 当前被调用的对象的class | #root.targetClass |
args | 当前方法参数组成的数组 | #root.args[0] |
caches | 当前被调用的方法使用的Cache | #root.caches[0].name |
- #root也可以省略,如下:
@Cacheable(value={"users", "xxx"}, key="caches[1].name")
public User find(User user) {
returnnull;
}
1.2.2 默认策略
默认的key的生成策略是通过KeyGenerator生成的。规则如下:
- 如果没有参数,则使用0作为key
- 如果只有一个参数,则使用该参数作为key
- 如果多个参数,就是用参数的hashcode作为key
1.3 condition属性
有时候可能不需要缓存所有的返回结果,这就要用到condition。
condition默认为空,表示会缓存所有的返回结果。其值是通过SpringEL表达式指定的,当表达式为true时进行缓存,为false时不进行缓存,每次调用该方法都会执行一次condition表达式。如下示例表示只有当user的id为偶数时才会进行缓存。
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
System.out.println("find user by user " + user);
return user;
}
1.4 unless属性
unless也是通过SpringEL表达式指定的,表达式返回值符合条件的排除掉,只缓存不符合条件的。
// 如果返回结果为null,则不进行缓存
@Cacheable(value = "getConfCustomer",unless="#result == null")
public ConfCustomerInfoVo getConfCustomer(String confCustomerCodes,String lotNo){
ConfCustomerInfoVo confCustomerInfoVo = null;
log.info("getConfCustomer-Redis调用");
return confCustomerInfoVo;
}
// 如果缓存结果为false,则不进行缓存
@Cacheable(value = "fruit", key = "#param", unless = "!#result")
public boolean isApple(String param) {
LatencyService.sleepAWhile(3);
if (param.equals("apple")) {
return true;
}
else {
return false;
}
}
二、@CachePut
使用@CachePut注解,该方法每次都会执行,会清除对应key的缓存然后再添加(或者更新缓存)
@CachePut和@Cacheable参数一样,@CachePut可以实现缓存的更新,使数据库和缓存保持一致。
@Cacheable更适用于查询方法,@CachePut更适用于更新方法。
官方强烈不推荐将 @Cacheable 和 @CachePut 注解到同一个方法。
// 更新数据库和缓存
@Override
@CachePut(value = "menuById", key = "#menu.id")
public Menu ReviseById(Menu menu) {
this.updateById(menu);
return menu;
}
// 读取缓存的时候,可以读取到最新的数据
@Override
@Cacheable(value = {"menuById"}, key = "#id")
public Menu findById(String id) {
Menu menu = this.getById(id);
if (menu != null){
System.out.println("menu.name = " + menu.getName());
}
return menu;
}
三、@CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或者类上。属性value、key、condition、allEntries 和 beforeInvocation。
其中value、key、condition和@Cacheable一样。
3.1 allEntries属性
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定allEntries为true时,Spring cache将忽略指定的key,删除掉所有的缓存。有时候需要清除所有的缓存,这样做比一个一个删除有效率的多。
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
3.2 beforeInvocation属性
清除操作默认是在方法执行成功之后触发的,即方法如果抛出异常未能成功返回则不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性为true时,Spring会在调用该方法之前清除缓存中的指定元素。
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
四、@Cacheable不起作用的场合
1、配置文件中启用缓存:spring.cache.type=redis
2、缓存的对象必须实现Serializable
public class ConfCustomerInfoVo extends BaseVo implements Serializable {
}
3、.SpringBootApplication中要加@EnableCaching注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableSwagger2
@EnableCaching
@EnableFeignClients(basePackages = {"com.newretail"})
@ComponentScan(basePackages = {"com.newretail"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、4.@Cacheable是基于Spring AOP代理类,内部方法调用是不走代理的,@Cacheable是不起作用的
public void get(){
this.getCacheValue("123");
}
@Cacheable(value="getCache")
public List getCacheValue(String id){
return ....
}