SpringBoot2使用@Cacheable注解时,Redis中保存的Value为java序列化乱码问题的解决办法及源码分析

说明:SpringBoot版本为2.1.6.RELEASE

看了许多同学的博客都是通过自定义RedisCacheManager组件的方式来解决,我这里换一种方式,采用自定义org.springframework.data.redis.cache.RedisCacheConfiguration组件的方式来解决,并附上源码分析过程

首先要明确SpringBoot Data在整合Redis作为Cache的实现方式后,组件之间的依赖关系变为:

CacheAutoConfiguration-->RedisCacheConfiguration(autoconfigure.cache)-->RedisCacheManager-->RedisCache-->RedisCacheConfiguration(redis.cache)

为什么使用@Cacheable注解后,保存的Value在Redis中是乱码,首先想到的是从RedisCache类中的put()方法入手。

put方法的逻辑如下图:

进入createAndConvertCacheKey(key)、serializeCacheValue(cacheValue)方法中,这里不贴代码了,可以知道对key和value的序列化规则都是从当前类的成员变量cacheConfig中获取配置的,而此成员变量cacheConfig对应的类型是org.springframework.data.redis.cache.RedisCacheConfiguration类:

进入org.springframework.data.redis.cache.RedisCacheConfiguration类中:

发现该类类头没有注解,推测它并不是容器中的一个组件,且对两个成员变量keySerializationPairvalueSerializationPair并没有赋予初始值,且唯一的构造器还是private私有的。

但此类中有两个static静态方法对keySerializationPairvalueSerializationPair成员变量进行了赋值,且返回一个实例对象:

分析到这里,我们就要知道是谁调用了此静态方法:

Ctrl+单击此defaultCacheConfig静态方法,发现是org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration配置类在向IOC容器中注入组件RedisCacheManager时,调用了此静态方法,见下图:

上图说明:在调用RedisCacheManager.builder方法创建RedisCacheManagerBuilder对象后,调用determineConfiguration方法进行装配RedisCacheConfiguration时调用的此defaultCacheConfig静态方法。

而在determineConfiguration方法中,调用此静态方法之前的前提条件是:this.redisCacheConfiguration不为空。否则就按照后面的逻辑对value实行Java序列化规则:JdkSerializationRedisSerializer

现在就分析当前类的成员变量this.redisCacheConfiguration的赋值逻辑,如下图:

发现在当前类的有参构造器中,它会从IOC容器中获取org.springframework.data.redis.cache.RedisCacheConfiguration组件并赋值给此成员变量。只不过IOC容器中并没有该可用组件,可以打断点看到:

解决办法:

通过以上的分析,那我们就可以自己手动向IOC容器中注册一个类型为org.springframework.data.redis.cache.RedisCacheConfiguration的组件,并参照determineConfiguration方法:调用serializeValuesWith方法对value的序列化规则改为json类型

/**
     * 注册自定义RedisCacheConfiguration组件,解决@Cacheable @Cacheput注解在向Redis中保存的Value是java序列化乱码的问题
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        config=config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
        return config;
    }

再次打断点观察RedisCacheManager组件的注册逻辑:就可以看到this.redisCacheConfiguration不为null,且对Value的序列化规则已经改成我们自定义的了。

原创不易,转载请指明出处,谢谢!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值