Spring 自身并没有实现缓存解决方案, 但是它对缓存功能提供了声明式的支持, 能够与多种流行的缓存实现进行集成。
Spring 的缓存抽象在很大程度上是围绕切面构建的。 在 Spring 中启用缓存时,会创建一个切面, 它触发一个或更多的 Spring 的缓存注解。
1 启用对缓存的支持
配置类上添加@EnableCaching
启用 Spring 对注解驱动缓存的支持。
在方法上添加@Cacheable
和@CacheEvict
注解使用 Spring 的缓存抽象。
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
1.1 配置缓存管理器
缓存管理器是 Spring 缓存抽象的核心, 它能够与多个流行的缓存实现进行集成。
Spring 3.1 内置五个缓存管理器实现
- SimpleCacheManager
- NoOpCacheManager
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhCacheCacheManager
Spring Data 又提供了两个缓存管理器:
- RedisCacheManager(来自于 Spring Data Redis 项目)
- GemfireCacheManager(来自于 Spring Data GemFire 项目)
1)使用单个
Redis 可以用来为 Spring 缓存抽象机制存储缓存条目, Spring Data Redis 提供了 RedisCacheManager, 这是 CacheManager 的一个实现。
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
@Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisCF) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(redisCF);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
2)使用多个
CompositeCacheManager 要通过一个或更多的缓存管理器来进行配置, 它会迭代这些缓存管理器, 以查找之前所缓存的值。
@Bean
public CacheManager cacheManager(
net.sf.ehcache.CacheManager cm,
javax.cache.CacheManager jcm) {
CompositeCacheManager cacheManager = new CompositeCacheManager();
List<CacheManager> managers = new ArrayList<CacheManager>();
managers.add(new JCacheCacheManager(jcm));
managers.add(new EhCacheCacheManager(cm))
managers.add(new RedisCacheManager(redisTemplate()));
cacheManager.setCacheManagers(managers);
return cacheManager;
}
2 为方法添加注解以支持缓存
所有注解都能运用在方法或类上。 放在类上时, 缓存行为会应用到这个类的所有方法上。
注 解 | 描 述 |
---|---|
@Cacheable | (读)调用前,先在缓存中查找方法的返回值。如有则返回,否则调用,返回值会放到缓存之中 |
@CachePut | (写)方法始终被调用,返回值放到缓存中 |
@CacheEvict | (删)在缓存中清除一个或多个条目 |
@Caching | 这是一个分组的注解, 能够同时应用多个其他的缓存注解 |
2.1 填充缓存
@Cacheable 和 @CachePut 都有一个名 value 属性,缓存名称
@Cacheable("spittleCache")
public Spittle findOne(long id) {
try {
return jdbcTemplate.queryForObject(
SELECT_SPITTLE_BY_ID,
new SpittleRowMapper(),
id);
} catch (EmptyResultDataAccessException e) {
return null;
}
}
1)将值放到缓存之中
有 @CachePut 注解的方法始终都会被调用, 而且它的返回值也会放到缓存中。
适合用在保存、修改操作上,即刻缓存。
2)自定义缓存 key
@Cacheable 和 @CachePut 都有一个名为 key 属性, 这个属性能够替换默认的 key, 它是通过一个 SpEL 表达式计算得到的。
在为缓存编写 SpEL 表达式的时候, Spring 暴露了一些很有用的元数据。
表 达 式 | 描 述 |
---|---|
#root.args | 传递给缓存方法的参数, 形式为数组 |
#root.caches | 该方法执行时所对应的缓存, 形式为数组 |
#root.target | 目标对象#root.targetClass 目标对象的类, 是#root.target.class的简写形式 |
#root.method | 缓存方法 |
#root.methodName | 缓存方法的名字, 是#root.method.name的简写形式 |
#result | 方法调用的返回值(不能用在@Cacheable注解上) |
#Argument | 任意的方法参数名(如#argName) 或参数索引(如#a0或#p0) |
@CachePut(value="spittleCache", key="#result.id")
Spittle save(Spittle spittle);
3)条件化缓存
@Cacheable 和 @CachePut 提供了两个属性用以实现条件化缓存: unless 和 condition。
unless 为 true 阻止添加到缓存中,condition 为 false 缓存被禁用。
@Cacheable(value="spittleCache" unless="#result.message.contains('NoCache')")
Spittle findOne(long id);
2.2 移除缓存条目
带有 @CacheEvict 注解的方法被调用,在缓存中移除。
适用于删除操作。
@CacheEvict("spittleCache")
void remove(long spittleId);