springBoot@Cache与redis结合

1.在此之前当我们在pom.xml dependencies 中引入redis starter依赖

<dependencies>
    <!--Redis 缓存-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
 
</dependencies>

配置文件配置

Spring:
    redis:
        host: 47.103.179.88
        port: 6379
        password: Redis123456
        max-wait: 30000 #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-active: 100 #连接池最大连接数(使用负值表示没有限制)
        max-idle: 20 #连接池中的最大空闲连接
        min-idle: 0 #连接池中的最小空闲连接
        timeout: 3000 #连接超时

RedisConfig.java配置类

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * retemplate相关配置
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 值采用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        return template;
    }

    

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 设置CacheManager的值序列化方式为Jackson2JsonRedisSerializer,默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 初始化一个RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        // 配置value序列化方式为Jackson2JsonRedisSerializer,key序列化方式采用默认的StringRedisSerializer
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
                RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofDays(1L));
        // 初始化RedisCacheManager
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
        return cacheManager;
    }
}

注意 cacheManager方法中.entryTtl(Duration.ofDays(1L)); 不能用defaultCacheConfig.entryTtl(Duration.ofDays(1L));只能按上面代码中这样写,objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);这个也是必要的当reids库中字段多了可以自动不解析并且不会抛异常

在方法上添加缓存注解

@Service
public class CacheService {
    // 添加缓存 ,下次再执行这个方法就从redis缓存中取数据
    //value 是指定业务名称,必须有,key是缓存key的名称 #name 表示是参数的name 
    //key = "#p0" 代表此方法的第一个参数
	@Cacheable(value = "names", key = "'names:' + #name") 
	public Hello hello(String name) {
		return hello;
	}
 
    //更新缓存 ,每次都会执行,更新数据到缓存中
	@CachePut(value = "names", key = "'names:' + #name")
	public Hello update(String name) {
		return hello;
	}
 
    //删除缓存
	@CacheEvict(value = "names", key = "'names:' + #name")
	public Hello delete(String name) {
		return hello;
	}

还有其他参数需要百度【比如插入缓存的条件等】

---------------------------------------------------------------------------------------------------------------------

设置不同的 过期时间

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * retemplate相关配置
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 值采用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        return template;
    }

   

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new RedisCacheManager(
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                this.getRedisCacheConfigurationWithTtl(1L),
                this.getRedisCacheConfigurationMap()
        );
    }

    /**
     * 指定 key 策略
     * @return Map<String, RedisCacheConfiguration>
     */
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = Maps.newHashMap();
        //进行过期时间配置
        redisCacheConfigurationMap.put("BasicDataCacheForever", this.getRedisCacheConfigurationWithTtl(-1L));
        return redisCacheConfigurationMap;
    }

    /**
     * 默认策略,未配置的 key 会使用这个
     * @param day 过期时间 1 为 1天 -1为无过期时间
     * @return
     */
    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(long day) {
        // 设置CacheManager的值序列化方式为Jackson2JsonRedisSerializer,默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 配置value序列化方式为Jackson2JsonRedisSerializer,key序列化方式采用默认的StringRedisSerializer
        RedisCacheConfiguration defaultCacheConfig;
        if(day > 0){
            defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofDays(day));
        }else {
            defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
        }
        return defaultCacheConfig;
    }

//    @Bean
//    public KeyGenerator wiselyKeyGenerator() {
//        return (target, method, params) -> {
//            StringBuilder sb = new StringBuilder();
//            sb.append(target.getClass().getName());
//            sb.append("." + method.getName());
//            if(params==null||params.length==0||params[0]==null){
//                return null;
//            }
//            String join = String.join("&", Arrays.stream(params).map(Object::toString).collect(Collectors.toList()));
//            String format = String.format("%s{%s}", sb.toString(), join);
//            return format;
//        };
//    }
}

注意:

spring cache 的原理是 基于动态生成的proxy代理机制来对方法的调用进行切面,如果对象的方法是 内部调用而不是外部引用,则会导致proxy失效,也就是说 @cacheable @cachePut@cacheEvict都会失效

解决方法

1.可以把removeGroupUserStatusCached方法单独抽取到另外一个类里面,通过代理类引入。
2.通过((GroupUserService)AopContext.currentProxy()).removeGroupUserStatusCached方法获取当前类的代理类;
3.通过ApplicationContext获取当前类的代理对象,GroupUserService groupUserService = springContextUtil.getBean(GroupUserService.class);

 

学习地址:

https://www.freesion.com/article/471336913/

https://blog.csdn.net/chengbinbbs/article/details/81128311

https://www.cnblogs.com/cyhbyw/p/8615816.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值