【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 ...
随机推荐
- jQuery签名插件jSignature
1.引入jSignature.min.js和jquery.min.js文件2.代码 <div id="signature"></div> 3.js 初始化 ...
- codeforce 378 div 2 F —— Drivers Dissatisfaction (最小生成树,LCA,倍增)
官方题解: If you choose any n - 1 roads then price of reducing overall dissatisfaction is equal to min(c ...
- servicemix-4.5.3 启动日志
karaf@root> log:display 2015-01-12 10:48:03,950 | WARN | rint Extender: 3 | XBeanNamespaceHandle ...
- H3C IEEE EUI-64格式
- 性能测试基础-开门篇3(LR常用函数介绍)
LR常用的函数,协议不一样函数会不一样,这里简单的介绍下HTTP\WEBSERVICE\SOCKET协议常用函数: HTTP: web_set_max_html_param_len("102 ...
- Linux 内核 低级 sysfs 操作
kobject 是在 sysfs 虚拟文件系统之后的机制. 对每个在 sysfs 中发现的目录, 有一个 kobject 潜伏在内核某处. 每个感兴趣的 kobject 也输出一个或多个属性, 它出现 ...
- 【35.86%】【POJ 1962】Corporative Network
Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 3943 Accepted: 1414 Description A very bi ...
- 【GYM101409】2010-2011 ACM-ICPC, NEERC, Western Subregional Contest
A-Area and Circumference 题目大意:在平面上给出$N$个三角形,问周长和面积比的最大值. #include <iostream> #include <algo ...
- C# 强转空会不会出现异常
有小伙伴问我强转 null 会不会出现异常,我告诉他,如果是引用类型那么不会,如果是值类型,那么会出现空异常 如果是引用类型,只要是空类型,是支持随意转换,如下面代码,这是可以运行 class Pro ...
- Webpack4不求人系列(1)
Webpack是一个现在Javascript应用程序的模块化打包器,在Webpack中JS/CSS/图片等资源都被视为JS模块,简化了编程.当Webpack构建时,会递归形成一个模块依赖关系图,然后将 ...