这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
可以通过注解或XML的方式配置Spring的缓存,本文仅阐述如何使用注解的方式,笔者认为这是一种更为优雅的方式。
如何配置一个CacheConfig
CacheConfig是用于声明所有缓存的一个统一的配置类,其标志是使用了@EnableCaching
注解的Java配置类,如下面的代码所示
@Configurable
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
其本质是创建了一个切面,根据注解和缓存的状态操作缓存中的数据。 @Bean方法用于会返回缓存管理器,Spring内置了五种内存管理器,分别为
- SimpleCacheManager:需要传入自定义的Collection用于缓存对象的管理。
- NoOpCacheManager:如果缓存中不存在,仅更新缓存但不会将实际结果返回。
- ConcurrentMapManager:使用ConcurrentMap实现的缓存。
- EhCacheCacheManager:基于EhCache实现的本地缓存,直接在JVM层面进行的缓存,速度快效率高
- CompositeCacheManager:可以配置多个缓存管理器,查找缓存条目时遍历查找
CompositeCacheManager的使用方法如下所示,将ConcurrentMapCacheManager和RedisCacheManager包含在一个CacheManager中。
@Bean
public CacheManager compositeCacheManager(ConcurrentMapCacheManager concurrentMapCacheManager, RedisCacheManager redisCacheManager) {
CompositeCacheManager compositeCacheManager = new CompositeCacheManager();
List<CacheManager> cacheManagerList = Lists.newArrayList();
cacheManagerList.add(concurrentMapCacheManager);
cacheManagerList.add(redisCacheManager);
compositeCacheManager.setCacheManagers(cacheManagerList);
return compositeCacheManager;
}
除了这五种Sping Data还引入了RedisCacheManager和GemfireCacheManager两个缓存管理器,这里笔者简单阐述一下RedisCacheManager的使用方法。
- 创建Redis的连接工厂Bean
- 创建RedisTemplate
- 创建Redis缓存管理器bean
@Configurable
@EnableCaching
public class CacheConfig {
@Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, SourceSystemDto> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, SourceSystemDto> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager redisCacheManager(RedisTemplate<String, SourceSystemDto> redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
}
为方法或类添加注解以支持缓存
在Spring中启用缓存会创建一个切面,触发一个或更多的Spring的缓存注解。Spring提供了以下四个注解,均可用于方法和类上,如果应用到类上会作用于所有方法。
-
@Cacheable
调用方法前先从缓存中取出,如果不存在则调用方法并将方法的返回值放到缓存中,适用于query方法。
-
@CachePut
调用方法前不会从缓存中取用,但会把返回值放到缓存,适用于save和update操作。
-
@CacheEvict
从缓存中移除对象。
-
@Caching
一个分组的注解,用于指定复杂的缓存规则。
@Cacheable
和@CachePut
注解支持value、condition、key和unless四个属性
属性 | 类型 | 描述 |
---|---|---|
value | String[] | 指定要使用缓存的名称 |
condition | String | SpEL表达式,仅为true的时候才会应用缓存 |
key | String | SpEL表达式,用来计算自定义缓存的key |
unless | String | SpEL表达式,如果为true则不会将结果放到缓存中 |
下面的代码演示使用的方法
public class EmployeeService {
/**
* 使用employeeCache缓存
* 使用id查找时使用缓存,将返回值的name和email作为key放入缓存中
*/
@Caching (
cacheable = {
@Cacheable(value = "employeeCache", key = "#id")
},
put = {
@CachePut(value = "employeeCacheName", key = "#result.name"),
@CachePut(value = "employeeCacheEmail", key = "#result.email")
}
)
public Employee getEmployee(String id) {
// TODO
}
/**
* 使用employeeCache缓存,自定义缓存为id,当enableCache为true时才会启用缓存
*/
@CachePut(value = "employeeCache", key = "#result.id", condition = "#employee.enableCache")
public Employee save(Employee employee) {
}
@CacheEvict(value = "employeeCache", key = "#id")
public void remove(String id) {
}
}
@Data
class Employee {
private String id;
private String name;
private String email;
private boolean enableCache;
}
在查询的getEmployee()方法上使用了@Caching
注解对多个注解进行了分组,该方法在查询时使用了employeeCache缓存,同时在返回时将id-对象、name-对象、email-对象分别放入不同的缓存中。
在新增/修改的saveEmployee()方法上使用了@CachePut
注解,将返回值解析为“id-对象”放入对应的缓存中。
在删除的remove()方法上使用了@CacheEvict
注解,在方法调用后将对应的缓存条目从缓存中移除。
@CacheEvict
注解额外提供了以下属性用于配置删除的策略
属性 | 类型 | 描述 |
---|---|---|
allEntries | boolean | 为true时删除缓存中的所有值 |
beforeInvocation | boolean | 为true时在调用前移除缓存条目,为false则在调用后移除(默认) |