【Spring Boot 源码解读】之 【为何引入了 Jedis 依赖最后用的还是 Lettuce 客户端?】
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
.....
例子代码:
我们在访问接口时,打印 RedisTemplate
的 ConnectionFactory
即可知道使用的是哪个客户端。
/**
* @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 客户端:
启动项目,访问接口,可是我们看到,控制台打印出来的竟然还是 Lettuce
的 ConnectionFactory
。
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
会按照顺序分别引入 LettuceConnectionConfiguration
和 JedisConnectionConfiguration
。而它们都会判断 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 客户端?】的更多相关文章
- Spring Boot源码(四):Bean装配
为了演示Spring中对象是如何创建并放到spring容器中,这里新建一个maven项目: 其中pom.xm文件中只引入了一个依赖: <dependencies> <dependen ...
- 曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(28)-- Spring的component-scan机制,让你自己来进行简单实现,怎么办
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 精尽Spring Boot源码分析 - 序言
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - Jar 包的启动实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - 剖析 @SpringBootApplication 注解
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - Condition 接口的扩展
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
随机推荐
- HDU 1236
水题~~但我做了很久: 题意:是中国人都懂了 思路:结构体排序: 以后要多用用重定义的排序手段,!!!!!多用!!多用!!多用!! #include<iostream> #include& ...
- JQuery操作select下拉框
JQuery操作select下拉框 获取Select选择的Text和Value $("#select_id").change(function(){//code...}); //为 ...
- git checkout简介
原文: http://web.mit.edu/~thefred/MacData/afs/sipb/project/git/git-doc/git-checkout.html git checkout ...
- css页面去除滚动条
注:滚动条是导致页面切换标签页闪动的原因 html{ /*隐藏滚动条,当IE下溢出,仍然可以滚动*/ -ms-overflow-style:none; /*火狐下隐藏滚动条*/ overflow:-m ...
- H3C系统调试的操作
- onCreate不加载布局
如果Activity重写的是 onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentS ...
- Windows Server Core Remote Manage Hyper-V
原帖:https://serverfault.com/questions/852144/how-do-i-remotely-manage-hyper-v-2016-standalone-via-win ...
- 关于hibernate5的映射文件和配置文件改变(转)
转自:https://blog.csdn.net/m0_37840000/article/details/78823716 配置文件: <!DOCTYPE hibernate-configura ...
- 【Linux】Linux下date,time等时间设置
date命令的帮助信息 [root@localhost source]# date --help用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] ...
- ELK学习实验010:Logstash简介
Logstash是具有实时流水线功能的开源数据收集引擎.Logstash可以动态统一来自不同来源的数据,并将数据规范化为您选择的目标.清除所有数据并使其民主化,以用于各种高级下游分析和可视化用例. 虽 ...