likes
comments
collection
share

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

作者站长头像
站长
· 阅读数 54

一、前言

背景:业务新需求需要依赖 Redis,避免影响原先业务,额外申请新的Redis实例。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

说白了,就是一个业务服务里创建了 2个 RestTemplate(Redis Client)用于分别访问 Redis。

原先项目里已经配置好一个 RestTemplate 去访问公共的 Redis,当前只需要配置新的 Redis 配置。

起手就是 3个步骤

  1. 配置 Redis 连接信息:存储连接信息
  2. 创建连接配置:ConnectionFactory
  3. 创建 RedisTemplate
Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

上手直接配置完,开发完业务代码,美滋滋😄💃。

突然,一抖机灵,想到配置新的Redis,会不会影响老的Redis连接 Client,

带这个问题,我写了demo简单测试了下

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

发现两个 redisTemplate 连接信息都指向一个 新的Redis:

  • 我本地模拟新的 Redis:IP为 localhost; 端口为 6380
Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

啊啊啊啊啊!出现新问题了。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

现在解决这个问题,方向可分为

  1. 不影响到原先的Redis配置(最优方式
  2. 分开配置 2个Redis配置信息(有风险,可能会影响到原先业务:序列化方式等)

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

二、排查过程:心路历程

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

初衷就是:不要影响到老的 Redis 配置等环境信息。

  • 不要再改别的地方的代码。

(1)遇事不决:问 ChatGPT

ChatGPT给出的答案差不多,步骤也是一样的3步骤,结论就是使用:注解 @Primary

使用 @Primary,就需要额外配置一份原先的配置,虽然能够解决当下问题,但同时也带来了新问题。

  • 问题 1 :Redis 的序列化方式不同的,这要看原先老的配置序列化方式是怎样的。需要保持一致。
  • 问题 2:引入新变化,那么引用的地方都要重新回归一遍,通过后才能上线。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

显然这不是最优解法,还要改配置,又要回归测试,麻烦的一啊。😭

为了彻底解决这个问题,我们需要探寻源码,找到其中的答案。

(2)刨根问底:为什么会影响到默认的 RestTemplate ?

在分析前,先了解下 SpringBoot 这几个注解:有用

条件注解作用条件注解解析类
ConditionalOnBeanApplicationContext 存在某些Bean时条件才成立OnBeanCondition
ConditionalOnClassclasspath 中存在某些Class时条件才成立OnClassCondition
ConditionnalOnMissingBeanApplicationContext 不存在某些Bean时才成立OnBeanCondition

SpringBoot 中有一个很重要的模块:spring-boot-autoconfigure

  • 该模块包含很多第三方依赖 AutoConfiguration(自动化配置类):KafkaAutoConfiguration、WebMvcAutoConfiguration 等。
  • 这些 AutoConfiguration 只会在特定的情况下才会生效,这些特定情况就是条件注解

1、自动装配过程

Spring Boot 中 RestTemplate 和 Redis 的自动装配是两个独立的过程,但它们都遵循 Spring Boot 的自动配置原则。

  • 这里主要分析 Redis 的自动装配过程。

Redis 的自动装配:主要由 RedisAutoConfiguration 类处理。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

  1. 检测到 RedisOperations 接口存在。
  2. 读取 Redis 相关的配置属性:即 RedisProperties
  3. 根据客户端库选择 Lettuce 或 Jedis 配置。
  4. 创建 RedisConnectionFactory。
  5. 创建 RedisTemplateStringRedisTemplate beans。

2、坑

RedisAutoConfiguration可以观察到

  1. 自动生效配置RedisProperties,这里主要读取配置文件中 spring.redis下的配置。
  2. 注解:@ConditionnalOnMissingBean,来创建 RestTemplate
  3. 不存在 Bean 名为 stringRedisTemplate,会自动创建。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

可以从上图看到,创建连接信息可以选择LettuceConnectionConfigurationJedisConnectionConfiguration

但从上图没看到:如何创建Redis连接信息(并尝试连接 Redis)

坑: @ConditionalOnMissingBean(RedisConnectionFactory.class)

  • 这个注解表示:只有在当前 Spring 上下文中不存在 RedisConnectionFactory 类型的 Bean 时,才会创建被该注解修饰的 Bean
  • 所以有第二个配置,原先默认配置就失效了。

这就解释了:为什么配置了新的Redis配置,2个Redis Client 都指向同一份配置。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

解决:创建初始化LettuceConnectionFactory时,不生成对应 Bean,即可。

Redis多数据源 RestTemplate 坑业务新需求需要依赖 Redis额外申请新的Redis实例。 说白了,就是

(3)小结

小结:

  1. 系统中没有自定义创建:Bean 名称为restTemplate,会自动创建默认的 restTemplate
  2. 自动会默认创建 restTemplatestringRedisTemplate两个 Bean
  3. 使用@Autowired注入restTemplate时候,会根据范型类别来选择。
    1. SpringBoot 会默认创建 RedisTemplateStringRedisTemplate beans。
    2. 默认创建的 RedisTemplate,实际是 RedisTemplate<Object, Object>
    3. 但如果使用 RedisTemplate<String, Object>就会报错

会报如下错误

No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' 
available: expected at least 1 bean which qualifies as autowire candidate. 
转载自:https://juejin.cn/post/7424908830902255668
评论
请登录