缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的。

配置缓存管理器

package cn.com.sm.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@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;
    }
}

为方法添加注解以支持缓存

填充缓存

所有注解都能运用在方法或类上。当将其放在单个方法上时,注解所描述的缓存行为只会运用到这个方法上。如果注解放在类级别的话,那么缓存行为就会应用到这个类的所有方法上。

//表明 Spring 在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中
@Cacheable("spittleCache")
public Spittle findOne(long id) {
  try {
    return jdbcTemplate.queryForObject(
      SELECT_SPITTLE_BY_ID,
      new SpittleRowMapper(),
      id);
  } catch (EmptyResultDataAccessException e) {
    return null;
  }
}

当 findOne() 被调用时,缓存切面会拦截调用并在缓存中查找之前以名 spittleCache 存储的返回值。

//表明 Spring 应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用
@CachePut("spittleCache");
Spittle save(Spittle spittle);

自定义缓存 key

@Cacheable 和 @CachePut 都有一个名为 key 属性,这个属性能够替换默认的 key,它是通过一个 SpEL 表达式计算得到的。任意的 SpEL 表达式都是可行的,但是更常见的场景是所定义的表达式与存储在缓存中的值有关,据此计算得到 key。(更多 SpEL 表达式请执行查阅其他资料)

对于 save() 方法来说,我们需要的键是所返回 Spittle 对象的 id 属性。表达式 #result 能够得到返回的 Spittle。借助这个对象,我们可以通过将 key 属性设置为 #result.id 来引用 id 属性:

@CachePut(value="spittleCache", key="#result.id")
Spittle save(Spittle spittle)

条件化缓存

Cacheable 和 @CachePut 提供了两个属性用以实现条件化缓存:unless 和 condition,这两个属性都接受一个 SpEL 表达式。 如果 unless 属性的 SpEL 表达式计算结果为 true,那么缓存方法返回的数据就不会放到缓存中。与之类似,如果 condition 属性的 SpEL 表达式计算结果为 false,那么对于这个方法缓存就会被禁用掉。

@Cacheable(value="spittleCache",
  unless="#result.message.contain('NoCache')",
  condition="#id >= 10")
Spittle findOne(long id);

如样例所示,unless 属性的表达式能够通过 #result 引用返回值。这是很有用的,这么做之所以可行是因为 unless 属性只有在缓存方法有返回值时才开始发挥作用。而 condition 肩负着在方法上禁用缓存的任务,因此它不能等到方法返回时再确定是否该关闭缓存。这 意味着它的表达式必须要在进入方法时进行计算,所以我们不能通过 #result 引用返回值。

移除缓存条目

使用场景:当缓存值不再合法时,我们应该确保将其从缓存中移除,这样的话,后续的缓存命中就不会返回旧的或者已经不存在的值,其中一个这样的场景就是数据被删除掉了。这样的话,SpittleRepository 的 remove() 方法就是使用 @CacheEvict 的绝佳选择:

@CacheEvict("spittleCache")
void remove(long spittlId)

WinRT
21 声望4 粉丝

临渊羡鱼,不如退而结网