美文网首页
Spring Boot整合Cache

Spring Boot整合Cache

作者: GIT提交不上 | 来源:发表于2020-04-30 15:08 被阅读0次

一、 JSR107规范

  Java Caching定义了5个核心接口,分别是CachingProvider、CacheManager、Cache、Entry、Expiry。

图1-1 接口关系图.png

  相关接口的含义请参考:

JSR107缓存规范

二、CacheManager & Cache接口

  本文选择RedisCacheManager和RedisCache作为示例:

图2.1 CacheManager接口继承关系.png 图2.2 Cache接口继承关系.png

二、核心注解

  Spring中缓存的核心注解包括:@Cacheable、@CacheEvict、@CachePut、@EnableCaching、@CacheConfig、 @Caching等。注解使用方法请参考官方文档:

Caching Data with Spring
史上最全的Spring Boot Cache使用与整合

三、关键步骤

  示例源码见:https://github.com/just-right/springbootcache

3.1 前期准备

  本文使用Docker安装MySQL和Redis,Docker相关命令请参考:

Docker安装及常见命令

  启动MySQL和Redis容器:

启动Redis容器
docker run -d --name MyRedis001 -p 6379:6379 redis:latest --requirepass "123456" --protected-mode no --bind 0.0.0.0
启动MySQL容器
docker run -itd --name mysql001 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:latest

3.2 序列化

  本文使用Jackson2JsonRedisSerializer作为缓存的序列化实现方式。核心代码如下所示:

private Jackson2JsonRedisSerializer<Object>  buildJackson2JsonRedisSerializer(){
      Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
      ObjectMapper om = new ObjectMapper();
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    //解决java.lang.ClassCastException: 
    //java.util.LinkedHashMap cannot be cast to XXX
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
      jackson2JsonRedisSerializer.setObjectMapper(om);
      return jackson2JsonRedisSerializer;
}

3.3 注入RedisTemplate

  注入RedisTemplate,核心代码如下所示:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    // 设置序列化
    Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.buildJackson2JsonRedisSerializer();
    // 配置redisTemplate
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(factory);
    RedisSerializer<?> stringSerializer = new StringRedisSerializer();
    redisTemplate.setKeySerializer(stringSerializer);// key序列化
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
    redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化

    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

3.4 注入CacheManager

  注入CacheManager,设置缓存默认过期时间,支持根据cacheNames配置指定的过期时间,核心代码如下所示:

参考链接:SpringBoot 2.X @Cacheable,redis-cache 如何根据key设置缓存时间?

@Bean
@Primary
public CacheManager redisCacheManager(RedisConnectionFactory factory) {
    return new RedisCacheManager(
        RedisCacheWriter.nonLockingRedisCacheWriter(factory),
        this.getRedisCacheConfigurationWithTtl(30), // 默认策略,未配置的 key 会使用这个
        this.getRedisCacheConfigurationMap() // 指定 key 策略
    );
}

   默认策略,设置过期时间30秒:

private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
    Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.buildJackson2JsonRedisSerializer();
    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
            RedisSerializationContext
                .SerializationPair
                .fromSerializer(jackson2JsonRedisSerializer)
            ).entryTtl(Duration.ofSeconds(seconds));
    return redisCacheConfiguration;
}

   定制策略,根据cacheNames(student)设置过期时间2秒:

private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
    Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
    redisCacheConfigurationMap.put(CacheConst.CACHE_STUDENT_NAME, this.getRedisCacheConfigurationWithTtl(2));
    return redisCacheConfigurationMap;
}

3.5 注入KeyGenerator

   注入KeyGenerator,定制缓存生成的key值,核心代码如下所示:

@Bean
public KeyGenerator cacheKeyGenerator() {
    return new StudentCacheKeyGenerator();
}

  实现KeyGenerator接口,取cacheNames和id作为key值,如:student:1。

public class StudentCacheKeyGenerator implements KeyGenerator {
   @Override
   public Object generate(Object o, Method method, Object... objects) {
       StringBuilder key = new StringBuilder(CacheConst.CACHE_STUDENT_NAME + ":");
       if (objects.length > 0) {
           for (Object object : objects) {
               if(object instanceof Student){
                   key.append(((Student) object).getId());
               }else {
                   key.append(object.toString());
               }
               break;
           }
       }
       return key.toString();
   }
}

四、测试

  测试Controller代码如下所示:

@RestController
@RequestMapping("student")
public class StudentController {
    @Resource
    private StudentService studentService;
    @GetMapping("selectOne")
    public Student selectOne(Integer id) {
        return this.studentService.queryById(id);
    }
    @PutMapping("updateOne")
    public Student updateOne(@RequestBody Student student) {
        return this.studentService.update(student);
    }
    @DeleteMapping("deleteOne")
    public boolean deleteOne(Integer id) {
        return this.studentService.deleteById(id);
    }
    @PostMapping("addOne")
    public Student addOne(@RequestBody Student student) {
        return this.studentService.insert(student);
    }
}

  添加打印SQL信息配置,添加配置后可以通过查看控制台是否打印SQL信息判断是否使用缓存或缓存是否过期

logging.level.com.example.cache.dao=debug

  使用PostMan进行测试,相关测试信息如下图所示。

图4-1 新增数据.png 图4-2 查询数据.png 图4-3 更新数据.png 图4-4 删除数据.png

相关文章

网友评论

      本文标题:Spring Boot整合Cache

      本文链接:https://www.haomeiwen.com/subject/sgpowhtx.html