1、Spring Boot 2.x 的两种 Redis 客户端

首先,我们都知道,从 Spring Boot 2.x 开始 Lettuce 已取代 Jedis 成为首选 Redis 的客户端。当然 Spring Boot 2.x 仍然支持 Jedis,并且你可以任意切换客户端。至于为什么会使用 Lettuce 替换 Jedis,大家可自行上网搜索。

2、我就是要使用 Jedis !

那么如果我们还是要在项目中使用 Jedis 作为 Redis 的客户端呢?是不是引入 Jedis 依赖即可?下面来试试。

引入依赖:

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

配置:

可以加上下面的关于连接池配置,或者不加,因为有默认值。

spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.min-idle=1
.....

例子代码:

我们在访问接口时,打印 RedisTemplateConnectionFactory 即可知道使用的是哪个客户端。

/**
* @author Howinfun
* @desc
* @date 2020/1/15
*/
@RestController
public class TestController { @Autowired
private RedisTemplate redisTemplate; @GetMapping("/test")
public String test(){
System.out.println(redisTemplate.getConnectionFactory());
return "hello";
}
}

神奇的 Lettuce 客户端:

启动项目,访问接口,可是我们看到,控制台打印出来的竟然还是 LettuceConnectionFactory

org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@21891c74

3、源码分析

Redis 的自动配置类:

首先看到 RedisAutoConfiguration

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
// 导入Lettuce和Jedis的连接配置类,而下面的创建RedisTemplate的RedisConnectionFactory在这两个配置类里都有生成。
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
} @Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
} @Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}

Lettuce 的连接配置类:

然后到LettuceConnectionConfiguration

@Configuration
// 当存在RedisClient.class时执行。ps:RedisClient是Lettuce依赖里面的类
@ConditionalOnClass({RedisClient.class})
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
// .... 省略 @Bean
// 当Spring容器不存在RedisConnectionFactory类型的bean对象时执行
@ConditionalOnMissingBean({RedisConnectionFactory.class})
public LettuceConnectionFactory redisConnectionFactory(ClientResources clientResources) throws UnknownHostException { LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration(clientResources, this.properties.getLettuce().getPool());
// 创建connectinFactory
return this.createLettuceConnectionFactory(clientConfig);
} // ..... 省略
}

Jedis 的连接配置类:

最后到JedisConnectionConfiguration

@Configuration
// 当同时存在GenericObjectPool.class, JedisConnection.class, Jedis.class时执行。ps:JedisConnection和Jedis都是Jedis依赖里面的类。GenericObjectPool是spring-boot-starter-data-redis里的类。
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
class JedisConnectionConfiguration extends RedisConnectionConfiguration { // .... 省略 @Bean
// 当Spring容器不存在RedisConnectionFactory类型的bean对象时执行
@ConditionalOnMissingBean({RedisConnectionFactory.class})
public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException { // 创建connectinFactory
return this.createJedisConnectionFactory();
} // .... 省略
}

总结:

从上面的源码分析可得。首先 Redis 的自动化配置依靠的是 RedisAutoConfiguration ,而 RedisAutoConfiguration 会按照顺序分别引入 LettuceConnectionConfigurationJedisConnectionConfiguration 。而它们都会判断 Spring容器 中是否存在 ConnectionFactory ,不存在则创建。正是这个引入的顺序,导致 LettuceConnectionConfiguration 要先比 JedisConnectionConfiguration 执行,所以当 LettuceConnectionConfiguration 创建了 ConnectionFactory 后, JedisConnectionConfiguration 判断不为空而不继续创建了。所以即使我们引入了 Jedis 依赖,最后也还是使用 Lettuce 客户端。

ps: Spring Boot 2.x 使用 Lettuce 的原理:首先是依靠 @Import 的引入顺序,然后是 spring-boot-starter-data-redis 里有 Lettuce 的依赖,而没有 Jedis 的依赖 。

4、如何正确使用 Jedis 客户端

从上面的源码分析看到,我们有两种方案,不过前提都是先引入 Jedis 依赖。

第一:直接去掉 Lettuce 的依赖

使 LettuceConnectionConfiguration 不能生效,因为 @ConditionalOnClass({RedisClient.class}) 的不再成立,导致其不会生效执行。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>

第二:在启动类的 @SpringBootApplication 去掉 RedisAutoConfiguration ,然后自己自定义一个 RedisAutoConfiguration

在自定义的 RedisAutoConfiguration 中修改 @Import 关于两个客户端的 ConnectionConfiguration 的引入顺序即可。但是其实这样做很没必要,还不如直接去掉依赖。

@SpringBootApplication(exclude = RedisAutoConfiguration.class)

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
// 先 Jedis 后 Lettuce
@Import({JedisConnectionConfiguration.class, LettuceConnectionConfiguration.class})
public class MyRedisAutoConfiguration {
public MyRedisAutoConfiguration() {
} // ...... 省略
}

最后

我们可以看到控制台打印的终于是 JedisConnectionFactory了。

org.springframework.data.redis.connection.jedis.JedisConnectionFactory@16c9834c

【Spring Boot 源码解读】之 【为何引入了 Jedis 依赖最后用的还是 Lettuce 客户端?】的更多相关文章

  1. Spring Boot源码(四):Bean装配

    为了演示Spring中对象是如何创建并放到spring容器中,这里新建一个maven项目: 其中pom.xm文件中只引入了一个依赖: <dependencies> <dependen ...

  2. 曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  3. 曹工说Spring Boot源码(28)-- Spring的component-scan机制,让你自己来进行简单实现,怎么办

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  4. 精尽Spring Boot源码分析 - 序言

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  5. 精尽Spring Boot源码分析 - Jar 包的启动实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  6. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  7. 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  8. 精尽Spring Boot源码分析 - 剖析 @SpringBootApplication 注解

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  9. 精尽Spring Boot源码分析 - Condition 接口的扩展

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

随机推荐

  1. 2006年NOIP普及组复赛题解

    题目涉及算法: 明明的随机数:简单模拟: 开心的金明:01背包: Jam的计数法:模拟: 数列:二进制. 明明的随机数 题目链接:https://www.luogu.org/problem/P1059 ...

  2. PHP实现微信小程序人脸识别刷脸登录功能

    首先我们先确认我们的百度云人脸库里已经上传了我们的个人信息照片 然后我们在后台写刷脸登陆的接口login我们要把拍照获取的照片存储到服务器 public function login(){    // ...

  3. linux常用命令速记

    一.命令提示符说明 1. [root@localhost ~]# root: 当前登录用户 localhost: 主机名 ~: 当前所在目录 #: 超级用户提示符($: 普通用户) 2. -rwxr- ...

  4. eclipse本地启动tomcat报错集锦

    1.eclipse本地添加tomcat服务器    打开Eclipse,单击“window”菜单,选择下方的“Preferences”: 找到Server下方的Runtime Environment, ...

  5. CodeForces 242E "XOR on Segment"(线段树)

    传送门 •题意 给你一个包含 n 个数的序列 a,定义序列上的两个操作: (1)$1,l,r\ :\ ans=\sum_{i=l}^{r}a_i$; (2)$2,l,r,x\ :\ \forall\ ...

  6. CF1063D Candies for Children

    CF1063D Candies for Children 分类讨论题 n<=1e11, 整体上先分n<=2e6与否讨论 len长度,ans贪心的人,p就是len这一段贪心的人 n<= ...

  7. vue-cli起项目步骤

    1.全局安装 vue-cli 老版本:npm install -g vue-cli  (npm uninstall vue-cli -g 卸载) 新版本:npm install -g @vue/cli ...

  8. 前端js页面跳转

    window.location.Reload() //刷新当前页面self.location=document.referrer;通过Request Headers中Referer获得上个页面的地址并 ...

  9. 【51.64%】【POJ 1330】Nearest Common Ancestors

    Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26416 Accepted: 13641 Description A roote ...

  10. boostrap-非常好用但是容易让人忽略的地方【1】:modal

    使用bootstrap框架好久了,在开发中也用到了或者遇到了很多的问题,所以跟大家分享一下 bootstrap modal 组件的样式 .modal-lg .modal-sm 说明:这个是bootst ...