Spring中的缓存技术

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

image.png

可以通过注解或XML的方式配置Spring的缓存,本文仅阐述如何使用注解的方式,笔者认为这是一种更为优雅的方式。

如何配置一个CacheConfig

CacheConfig是用于声明所有缓存的一个统一的配置类,其标志是使用了@EnableCaching注解的Java配置类,如下面的代码所示

1
2
3
4
5
6
7
8
9
10
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中。

1
2
3
4
5
6
7
8
9
java复制代码@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的使用方法。

  1. 创建Redis的连接工厂Bean
  2. 创建RedisTemplate
  3. 创建Redis缓存管理器bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
java复制代码@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则不会将结果放到缓存中

下面的代码演示使用的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
java复制代码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则在调用后移除(默认)

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%