SpringBoot2.x操作缓存的新姿势

一、介绍

spring cache 是spring3版本之后引入的一项技术,可以简化对于缓存层的操作,spring cache与springcloud stream类似,都是基于抽象层,可以任意切换其实现。

其核心是CacheManager、Cache这两个接口,所有由spring整合的cache都要实现这两个接口、Redis的实现类则是 RedisCache 和 RedisManager。

二、使用

1、查询

需要导入的依赖

<code><dependency>    <groupid>org.springframework.boot/<groupid>    <artifactid>spring-boot-starter-cache/<artifactid>/<dependency><dependency>    <groupid>org.springframework.boot/<groupid>    <artifactid>spring-boot-starter-data-redis/<artifactid>/<dependency>/<code>

编写对于cache的配置

<code>@EnableCaching@SpringBootConfigurationpublic class CacheConfig {    @Autowired    private RedisConnectionFactory connectionFactory;    @Bean // 如果有多个CacheManager的话需要使用@Primary直接指定那个是默认的    public RedisCacheManager cacheManager() {        RedisSerializer<string> redisSerializer = new StringRedisSerializer();        Jackson2JsonRedisSerializer<object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);        ObjectMapper om = new ObjectMapper();        // 防止在序列化的过程中丢失对象的属性        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);        // 开启实体类和json的类型转换        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);        jackson2JsonRedisSerializer.setObjectMapper(om);        // 配置序列化(解决乱码的问题)        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()   .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))             .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))                // 不缓存空值                .disableCachingNullValues()                // 1分钟过期                .entryTtl(Duration.ofMinutes(1))                ;        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)                .cacheDefaults(config)                .build();        return cacheManager;    }}/<object>/<string>/<code>

进行以上配置即可使用springboot cache了,还有一个key的生成策略的配置(可选)

<code>@Beanpublic KeyGenerator keyGenerator() {    return (target, method, params) -> {        StringBuffer key = new StringBuffer();        key.append(target.getClass().getSimpleName() + "#" + method.getName() + "(");        for (Object args : params) {            key.append(args + ",");        }        key.deleteCharAt(key.length() - 1);        key.append(")");        return key.toString();    };}/<code>

注意:如果配置了KeyGenerator ,在进行缓存的时候如果不指定key的话,最后会把生成的key缓存起来,如果同时配置了KeyGenerator 和key则优先使用key。推荐:深入SpringBoot核心注解原理

在controller或者service的类上面添加 @CacheConfig ,注解里面的参数详情见下表:

SpringBoot2.x操作缓存的新姿势

在标有@CacheConfig的类里面编写一个查询单个对象的方法并添加 @Cacheable注解

<code>@Cacheable(key = "#id", unless = "#result == null") @PatchMapping("/course/{id}")public Course courseInfo(@PathVariable Integer id) {    log.info("进来了 .. ");    return courseService.getCourseInfo(id);}/<code>

执行完该方法后,执行结果将会被缓存到Redis:

SpringBoot2.x操作缓存的新姿势

@Cacheable注解中参数详情见下表:

SpringBoot2.x操作缓存的新姿势

2、修改

编写一个修改的方法,参数传对象,返回值也改成这个对象

<code>@PutMapping("/course")public Course modifyCoruse(@RequestBody Course course) {    courseService.updateCourse(course);    return course;}/<code>

在方法上面添加 @CachePut(key = "#course.id") 注解,这个注解表示将方法的返回值更新到缓存中,注解中的参数和 @Cacheable 中的一样,这里就略过了。扩展:SpringBoot内容聚合

3、删除

编写删除方法,在方法上添加@CacheEvict 注解

<code>@CacheEvict(key = "#id")@DeleteMapping("/course/{id}")public void removeCourse(@PathVariable Integer id) {   courseService.remove(id);}/<code>

@CacheEvict 的参数信息见下表:

SpringBoot2.x操作缓存的新姿势

三、 基于代码的Cache的使用

因为我们有配置的CacheManager,所以可以利用RedisCacheManager对象去手动操作cache,首先将CacheManager注入进来:

<code>@Resource private CacheManager cacheManager;@PatchMapping("/course2/{id}")public Course course2(@PathVariable Integer id) {    // 获取指定命名空间的cache    Cache cache = cacheManager.getCache("course");    // 通过key获取对应的value    Cache.ValueWrapper wrapper = cache.get(2);    if (wrapper == null) {        // 查询数据库        Course course = courseService.getCourseInfo(id);        // 加入缓存        cache.put(course.getId(), course);        return course;    } else {        // 将缓存的结果返回        // 因为配置了enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);        // 所以在进行强转的时候不会报错        return (Course) wrapper.get();     }}/<code> 


分享到:


相關文章: