【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 ...
随机推荐
- H3C PPP MP配置示例一
- spark mllib docs,MLlib: RDD-based API
MLlib: RDD-based API This page documents sections of the MLlib guide for the RDD-based API (the spar ...
- mybatis PageHelper分页插件 和 LRU算法缓存读取数据
分页: PageHelper的优点是,分页和Mapper.xml完全解耦.实现方式是以插件的形式,对Mybatis执行的流程进行了强化,添加了总数count和limit查询.属于物理分页. 一.首先注 ...
- 2018-8-10-WPF-好看的矢量图标
title author date CreateTime categories WPF 好看的矢量图标 lindexi 2018-08-10 19:16:53 +0800 2018-5-16 11:4 ...
- 2019-4-12-WPF-绑定的默认模式
title author date CreateTime categories WPF 绑定的默认模式 lindexi 2019-04-12 09:38:58 +0800 2019-04-12 09: ...
- H5 数据存储localStorage
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- H5 网络状态接口
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- linux scull 中的读写代码
读和写方法都进行类似的任务, 就是, 从和到应用程序代码拷贝数据. 因此, 它们的原型 相当相似, 可以同时介绍它们: ssize_t read(struct file *filp, char u ...
- CCPC 2018 吉林 C "JUSTICE" (数学)
传送门 参考资料: [1]:https://blog.csdn.net/mmk27_word/article/details/89789770 题目描述 Put simply, the Justice ...
- js中的克隆
1.如果克隆对象是基本类型,直接复制就可以 <script type="text/javascript"> var str1 = 'abc' var str2 = st ...