第九章:(7)Spring Boot 与 缓存 之 自定义 CacheManager

一、测试缓存

  1、默认情况

    默认情况,SpringBoot 会使用 SimpleCacheConfiguration 缓存配置类。

    然后创建一个 ConcurrentMapCacheManager 缓存管理器,可以获取 ConcurrentMap 来作为缓存组件使用。

  2、使用 Redis

  (1)引入 redis 的 starter 后,RedisCacheConfiguration 缓存配置类就会生效,会创建一个 RedisCacheManager。

    

  (2)RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件,RedisCache 通过操作 Redis 来存取数据;

  (3)测试

    @Cacheable(cacheNames = {"emp"})
    public Employee getEmpById(Integer id) {
        System.out.println("查询" + id +"号员工");
        return employeeMapper.getEmpById(id);
    }

    会以 Redis 做为缓存来存取数据。

    

    默认保存数据 k-v 都是 Object,利用序列化保存的,如何保存为 JSON呢?

  (4)RedisCacheManager

    引入 redis 的 starter之后,cacheManager 变为 RedisCacheManager。

    默认创建的 RedisCacheManager 在操作 redis 的时候 RedisTemplate<Object, Object>。

    

    RedisTemplate<Object, Object> 是默认使用JDK的序列化机制。

    

  (5)如果我们想要保存为 JSON 格式就可以自定义 CacheManager。

二、自定义 CacheManager

  1、自定义操作 Employee 的 CacheManager

  (1)自定义 RedisTemplate

    @Bean
    public RedisTemplate<Object, Employee> empRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {

        RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>();
        //设置默认的序列化器
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Employee>(Employee.class));
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

  (2)自定义 CacheManager

    //CacheManagerCustomizers 可以来定制缓存的一些规则
    @Bean
    public RedisCacheManager empCacheManager(RedisTemplate<Object, Employee> empRedisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate);
        //使用前缀,将 CacheName 作为key 的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }

  (3)测试

    @Cacheable(cacheNames = {"emp"})
    public Employee getEmpById(Integer id) {
        System.out.println("查询" + id +"号员工");
        return employeeMapper.getEmpById(id);
    }

    现在就可以保存为 JSON 格式的 Employee 数据了。

    

    但是,还有一个问题?如果存取的是其他的 JavaBean 呢?

    /**
     * 缓存的数据能存入 redis
     * 第二次从缓存中查询就不能反序列化回来
     * 存的是 dept 的 json 数据, CacheManager 默认使用RedisTemplate<Object, Employee> empRedisTemplate 来操作 Redis 的
     *
     *
     * @param id
     * @return
     */
    @Cacheable(cacheNames = "dept")
    public Department getDeptById(Integer id){
        System.out.println("getDeptById查询部门:" + id);
        return departmentMapper.getDeptById(id);
    }

    出错了!!!

     原因:存的是 dept 的 json 数据, CacheManager 默认使用RedisTemplate<Object, Employee> empRedisTemplate 来操作 Redis 的

  2、自定义操作 Department 的 CacheManager

  (1)自定义 RedisTemplate

    @Bean
    public RedisTemplate<Object, Department> deptRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {

        RedisTemplate<Object, Department> template = new RedisTemplate<Object, Department>();
        //设置默认的序列化器
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Department>(Department.class));
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

  (2)自定义 CacheManager

    @Bean
    public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate);
        //使用前缀,将 CacheName 作为key 的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }

  (3)测试

    但是现在容器中有两个 CacheManager(EmpCacheManager 和 DeptCacheManager),所以操作缓存的时候还需要指定 CacheManager。

    可以使用 @CacheConfig 在类上进行统一的配置。

@CacheConfig(cacheNames = {"dept"}, cacheManager = "deptCacheManager")
@Service
public class DepartmentService {

    @Autowired
    DepartmentMapper departmentMapper;

    @Cacheable(cacheNames = "dept")
    public Department getDeptById(Integer id){
        System.out.println("getDeptById查询部门:" + id);
        return departmentMapper.getDeptById(id);
    }
}

    也可以在 @Cacheable 注解上面指定:

@Cacheable(cacheNames = "dept", cacheManager = "deptCacheManager")

     此时就可以同时使用 EmpCacheManager 与 DeptCacheManager了。

    

  (4)以编码方式使用缓存

    @Qualifier("deptCacheManager")
    @Autowired
    RedisCacheManager deptCacheManager;

    //直接使用缓存管理器得到缓存,进行调用即可
    public Department getDept(Integer id){
        System.out.println("getDeptById查询部门:" + id);
        Department dept = departmentMapper.getDeptById(id);
        //获取某个缓存
        Cache cache = deptCacheManager.getCache("dept");

        cache.put("dept:1", dept);
        return dept;
    }

  3、指定首选的 CacheManager

    当在容器中配置了多个 CacheManager,如果没有指定使用哪个 CacheManager,就会报错,所以需要指定一个默认的首选配置,我们可以把 RedisCacheConfiguration 中的RedisCacheManager 作为首选的CacheManager。

    代码示例:

    //CacheManagerCustomizers 可以来定制缓存的一些规则
    @Bean
    public RedisCacheManager empCacheManager(RedisTemplate<Object, Employee> empRedisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate);
        //使用前缀,将 CacheName 作为key 的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }

    @Bean
    public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate);
        //使用前缀,将 CacheName 作为key 的前缀
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }


    @Primary //将某个缓存管理器作为默认使用的
    @Bean
    public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);

        return cacheManager;
    }
原文地址:https://www.cnblogs.com/niujifei/p/15732655.html