spring cache学习(一):spring cache注解简单了解

  最近了解到spring cache非常方便的对一些方法的结果值做了缓存,结合spring boot中的注解使用更加方便,这里去学习一下。

在做分类视图可配置化时,发现组织架构的接口加了@cacheable注解,这里就去了解一下spring的cache支持。

1.相关注解

spring boot cache 提供了一些注解方便做cache应用。

(1)@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置

(2)@Cacheable:主要方法返回值加入缓存。同时在查询时,会先从缓存中取,若不存在才再发起对数据库的访问。

(3)@CachePut:配置于函数上,能够根据参数定义条件进行缓存,与@Cacheable不同的是,每次回真实调用函数,所以主要用于数据新增和修改操作上。

(4)@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除对应数据

(5)@Caching:配置于函数上,组合多个Cache注解使用。


@Cacheable

@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

  • valuecacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
  • key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
  • condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。
  • unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
  • keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
  • cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
  • cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

    作用和配置方法

参数 解释 example
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:
@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @Cacheable(value=”testcache”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 @Cacheable(value=”testcache”,condition=”#userName.length()>2”)
    /** * 根据ID获取Tasklog * @param id * @return */
    @Cacheable(value = CACHE_KEY, key = "#id",condition = "#result != null")
    public Tasklog findById(String id){
        System.out.println("FINDBYID");
        System.out.println("ID:"+id);
        return taskLogMapper.selectById(id);
    }

@CachePut

@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用

    作用和配置方法

参数 解释 example
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 @CachePut(value=”my cache”)
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @CachePut(value=”testcache”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 @CachePut(value=”testcache”,condition=”#userName.length()>2”)

    /** * 添加tasklog * @param tasklog * @return */
    @CachePut(value = CACHE_KEY, key = "#tasklog.id")
    public Tasklog create(Tasklog tasklog){
        System.out.println("CREATE");
        System.err.println (tasklog);
        taskLogMapper.insert(tasklog);
        return tasklog;
    }

@CacheEvict

@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空

    作用和配置方法

参数 解释 example
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 @CacheEvict(value=”my cache”)
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @CacheEvict(value=”testcache”,key=”#userName”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 @CacheEvict(value=”testcache”,condition=”#userName.length()>2”)
allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 @CachEvict(value=”testcache”,beforeInvocation=true)
    /** * 根据ID删除Tasklog * @param id */
    @CacheEvict(value = CACHE_KEY, key = "#id")
    public void delete(String id){
        System.out.println("DELETE");
        System.out.println("ID:"+id);
        taskLogMapper.deleteById(id);
    }

@CacheConfig

所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法写别的名字,那么依然以方法的名字为准。

@CacheConfig是一个类级别的注解。

/** * 测试服务层 */
@Service
@CacheConfig(value = "taskLog")
public class TaskLogService {

    @Autowired  private TaskLogMapper taskLogMapper;
    @Autowired  private net.sf.ehcache.CacheManager cacheManager;

    /** * 缓存的key */
    public static final String CACHE_KEY   = "taskLog";

    /** * 添加tasklog * @param tasklog * @return */
    @CachePut(key = "#tasklog.id")
    public Tasklog create(Tasklog tasklog){
        System.out.println("CREATE");
        System.err.println (tasklog);
        taskLogMapper.insert(tasklog);
        return tasklog;
    }

    /** * 根据ID获取Tasklog * @param id * @return */
    @Cacheable(key = "#id")
    public Tasklog findById(String id){
        System.out.println("FINDBYID");
        System.out.println("ID:"+id);
        return taskLogMapper.selectById(id);
    }
}


@Caching

有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。 

@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User save(User user) {
}


自定义缓存注解

比如之前的那个@Caching组合,会让方法上的注解显得整个代码比较乱,此时可以使用自定义注解把这些注解组合到一个注解中,如:

@Caching(put = {
    @CachePut(value = "user", key = "#user.id"),
    @CachePut(value = "user", key = "#user.username"),
    @CachePut(value = "user", key = "#user.email")
})
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface UserSaveCache {
}

这样我们在方法上使用如下代码即可,整个代码显得比较干净。

@UserSaveCache
public User save(User user){}

2.zanbootDemo进行测试

(1)cache相关注解必须在spring所管理的bean容器中,这样才能使缓存生效

(2)启动类中要加入@EnableCaching注解支持缓存

package com.zhanglijun.demo.zanbootdemo.domain.spring.cache;

import lombok.Data;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

/**
 * cache应用类
 * @author 夸克
 * @create 2018/7/5 14:25
 */
@Data
@CacheConfig(cacheNames = "texts")
@Component // spring cache生效必须初始化为一个bean
public class CacheObject {

    private String text;

    @Cacheable(value = "texts")
    public String query() {
        System.out.println("调用方法内部,未走缓存");
        return "text_query";
    }

    @CachePut(value = "texts")
    public String update() {
        return "text_updated";
    }

    @CacheEvict(value = "texts")
    public String delete() {
        return "text_deleted";
    }

}





package com.zhanglijun.demo.zanbootdemo.util;

import com.zhanglijun.demo.zanbootdemo.BaseTest;
import com.zhanglijun.demo.zanbootdemo.domain.spring.cache.CacheObject;
import javax.annotation.Resource;
import org.junit.Test;
import org.springframework.cache.CacheManager;

/**
 * @author 夸克
 * @create 2018/7/5 14:32
 */
public class SpringCacheTest extends BaseTest {

    @Resource
    private CacheObject cacheObject;

    // 注入cacheManager 方便debug
    @Resource
    private CacheManager cacheManager;

    @Test
    public void testCache() {

        System.out.println("===================第一次调用查询方法====================");
        String query = cacheObject.query();
        System.out.println("查询值为" + query);

        System.out.println("===================第二次调用查询方法====================");
        String query1 = cacheObject.query();
        System.out.println("查询值为" + query1);

        // 更新缓存
        cacheObject.update();
        System.out.println("===================执行完更新缓存调用查询====================");
        // 再次查询缓存
        String query3 = cacheObject.query();
        System.out.println("查询值为" + query3);


        // 删除缓存
        cacheObject.delete();
        System.out.println("===================执行完删除缓存调用查询====================");
        // 再次执行查询
        String query2 = cacheObject.query();
        System.out.println("查询值为" + query2);

    }
}




执行结果:


猜你喜欢

转载自blog.csdn.net/zlj1217/article/details/80928122