一、測試緩存
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; }