6 Spring Cache

Wu Jun 2018-12-18 21:52:29
06 Spring > 05 Data.md

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 内置五个缓存管理器实现

Spring Data 又提供了两个缓存管理器:

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);