Skip to content

springboot集成springcache

springboot使用springcache可以快速的集成缓存操作,在查找的时候先获取缓存,添加、修改和删除的时候更新数据库的同时更新缓存

一、包依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

二、配置文件

spring:
  cache:
    #指定缓存类型为redis
    type: redis

三、配置信息加载

这里需要注意,把**@EnableCaching**注解开启

这里加载了两个配置对象RedisCacheManager主要是针对springcache的过期时间配置,默认过期时间是一个小时,和序列化配置,序列化配置为json格式

@Configuration
@EnableCaching
public class RedisConfig {

    /**
     * 自定义spring cache缓存key规则
     * @return org.springframework.cache.interceptor.KeyGenerator
     * @author lcy
     * @date 2021/6/29 14:17
     **/
    @Bean
    public KeyGenerator keyGenerator(){
        return (Object target,Method method,Object... params) ->
        {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

    /**
     * 默认spring cache配置  过期时间一个小时
     * @param connectionFactory 连接工厂
     * @return org.springframework.data.redis.cache.RedisCacheManager
     * @author lcy
     * @date 2021/6/29 14:14
     **/
    @Bean
    @Primary
    public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory){
        RedisCacheConfiguration config = instanceConfig(3600L);
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    /**
     * spring cache配置  过期时间一天
     * @param connectionFactory 连接工厂
     * @return org.springframework.data.redis.cache.RedisCacheManager
     * @author lcy
     * @date 2021/6/29 14:14
     **/
    @Bean
    public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory){

        RedisCacheConfiguration config = instanceConfig(3600 * 24L);
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }

    /**
     * spring cache的过期时间配置
     * @param ttl 过期时间,以秒为单位
     * @return org.springframework.data.redis.cache.RedisCacheConfiguration
     * @author lcy
     * @date 2021/6/29 14:13
     **/
    private RedisCacheConfiguration instanceConfig(Long ttl){
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(serializingObjectMapper());
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(ttl))
                .disableCachingNullValues()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));

    }

    /**
     * 获取序列化的jackson对象
     * @return com.fasterxml.jackson.databind.ObjectMapper
     * @author lcy
     * @date 2021/6/29 14:12
     **/
    public ObjectMapper serializingObjectMapper(){
        //创建jsr310包下的javaTimeModule对象,其中包含了jdk8以后的时间类型序列化和反序列化配置
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        //LocalDateTime序列化设置为yyyy-MM-dd HH:mm:ss
        LocalDateTimeSerializer localDateTimeSerializer =
                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        //增加序列化到配置当中
        javaTimeModule.addSerializer(LocalDateTime.class,localDateTimeSerializer);
        //LocalDateTime反序列化设置为yyyy-MM-dd HH:mm:ss
        LocalDateTimeDeserializer localDateTimeDeserializer =
                new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        //增加反序列化到配置当中
        javaTimeModule.addDeserializer(LocalDateTime.class,localDateTimeDeserializer);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        //注册配置--jdk8类型
        objectMapper.registerModule(javaTimeModule);
        // 去掉各种@JsonSerialize注解的解析
        objectMapper.configure(MapperFeature.USE_ANNOTATIONS,false);
        // 只针对非空的值进行序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 将类型序列化到属性json字符串中
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);
        objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);

        return objectMapper;
    }
}

四、注解使用和介绍

注解支持两种使用方式:

  • 类注解:类上必须加@CachaConfig(cacheNames="xxx") 在同一个redis必须唯一,默认是userCache。如果多个不一样的类都使用默认值会有问题。一般这种方式不经常使用
  • 方法注解:在方法上去细分功能的注解,这种方式经常使用。

下面是注解属性的介绍,与下面的注解都适用

  • value:缓存的名称,可以有多个

  • key:缓存key的规则,可以使用springEL表达式,如果没有设置keyGenerator,默认是方法参数组合。设置了以后取keyGenerator的结果

  • condition 缓存条件,可以使用springEL表达式,返回true的时候才缓存

  • keyGenerator:不配置使用配置类里的默认对象,配置的话需要改为配置类的方法名称,即bean

  • cacheManager:不配置使用配置类里的默认对象,配置的话需要改为配置类的方法名称,即bean

例如:

//根据方法名称使用key,这里会出现不同的用户参数也会获取到相同的结果
@Cacheable(value = {"redis"}, key="#root.methodName")
//根据参数对象的id添加数据
@Cacheable(value = {"redis"}, key="#param.id")
//如果入参不是对象,根据入参的参数数组添加数据
@Cacheable(value = {"redis"}, key="#root.args[0]")
//分页获取数据
@Cacheable(value = {"product_page"},key="#root.methodName + #page+'_'+#size")

以下是方法注解介绍

4.1、@Cacheable

如果在缓存中存在结果则直接返回,不存在查询数据库,即结果存储在缓存中的方法,方便后续使用(具有相同参数)时,返回缓存中的值而不必执行该方法。

这里有一个注解,可以防止缓存击穿:

  • sync:将缓存锁住,只有一个线程可以进入计算,而阻塞其它线程,直到返回结果更新到缓存当中。true为开启,默认不开启

4.2、@CachePut

修改数据的时候更新缓存,当需要更新缓存而不干扰方法执行时,可以使用@cachePut注解,始终执行该方法并且将其结果放入缓存中。

4.3、@CacheEvict

删除数据的时候同时删除缓存对于从缓存中删除陈旧或未使用的数据非常有用,指示缓存范围内的驱逐是否需要执行而不仅仅是一个条目驱逐

这里有个注解属性需要注意

  • beforeInvocation = false
    • 缓存的清除是否在方法之前执行 ,默认代表缓存清除操作是在方法执行之后执行;
    • 如果出现异常缓存就不会清除
  • beforeInvocation = true
    • 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除

4.4、@Caching

组合注解,当方法里需要同时操作多个key的时候使用

例如:

@Caching(
            cacheable = {
                    @Cacheable(value = "redis",keyGenerator = "keyGenerator")
            },
            put = {
                    @CachePut(value = "redis",key = "#id"),
                    @CachePut(value = "redis",key = "'redis:'+#id")
            }
    )

五、使用redis session外部redis共享session

通过session实现登录态的控制的时候可以使用

5.1、依赖

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

5.2配置文件

maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 之后,原 Spring Boot 的 server.session.timeout 属性不再生效。