在做安卓app项目,springboot写接口整合redis用RedisTemplate确实挺方便。在Android Studio模拟器里测试app功能,大概10几分钟后遇到请求数据失败,看接口报错了:
redis Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to …
原因
于是本着我又不是springboot开发者怎么知道ta为什么报错的思想打开百度,看到一些网友说,springboot1.x默认使用的是jedis,到了Springboot2.x就默认使用了lettuce。Springboot2.x是如何默认使用了lettuce,这得去研究下里面的部分代码。我们可以可进入到Springboot2.x自动装配模块的redis部分,其中有一个RedisAutoConfiguration类,其主要作用是对Springboot自动配置连接redis类:
@Configuration( proxyBeanMethods = false ) @ConditionalOnClass({RedisOperations.class}) @EnableConfigurationProperties({RedisProperties.class}) @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) public class RedisAutoConfiguration { public RedisAutoConfiguration() { } ...... }
这里只需要关注里面的一行注解:
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
这就意味着使用spring-boot-starter-data-redis依赖时,可自动导入lettuce和jedis两种驱动,按理来说,不会同时存在两种驱动,这样没有太大意义,因此,这里的先后顺序就很重要了,为什么这么说呢?
分别进入到LettuceConnectionConfiguration.class与JedisConnectionConfiguration.class当中,各自展示本文需要涉及到的核心代码:
//LettuceConnectionConfiguration @ConditionalOnClass({RedisClient.class}) class LettuceConnectionConfiguration extends RedisConnectionConfiguration { ...... @Bean @ConditionalOnMissingBean({RedisConnectionFactory.class}) LettuceConnectionFactory redisConnectionFactory(ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers, ClientResources clientResources) throws UnknownHostException { LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration(builderCustomizers, clientResources, this.getProperties().getLettuce().getPool()); return this.createLettuceConnectionFactory(clientConfig); } } //JedisConnectionConfiguration @ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class}) class JedisConnectionConfiguration extends RedisConnectionConfiguration { ...... @Bean @ConditionalOnMissingBean({RedisConnectionFactory.class}) JedisConnectionFactory redisConnectionFactory(ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException { return this.createJedisConnectionFactory(builderCustomizers); } }
可见,LettuceConnectionConfiguration.class与JedisConnectionConfiguration.class当中都有一个相同的注解 @ConditionalOnMissingBean({RedisConnectionFactory.class}),这是说,假如RedisConnectionFactory这个bean已经被注册到容器里,那么与它相似的其他Bean就不会再被加载注册,简单点说,对LettuceConnectionConfiguration与JedisConnectionConfiguration各自加上 @ConditionalOnMissingBean({RedisConnectionFactory.class})注解,两者当中只能加载注册其中一个到容器里,另外一个就不会再进行加载注册。
那么,问题就来了,谁会先被注册呢?
这就回到了上面提到的一句,@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})这一句里的先后顺序很关键,LettuceConnectionConfiguration在前面,就意味着,LettuceConnectionConfiguration将会被注册。
可见,Springboot默认是使用lettuce来连接redis的。
解决
当我们引入spring-boot-starter-data-redis依赖包时,其实就相当于引入lettuce包,这时就会使用lettuce驱动,若不想使用该默认的lettuce驱动,直接将lettuce依赖排除即可。
<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>
然后再引入jedis依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
这样,在进行RedisAutoConfiguration的导入注解时,因为没有找到lettuce依赖,故而这注解@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})的第二个位置上的JedisConnectionConfiguration就有效了,就可以被注册到容器了,当做springboot操作redis的驱动。
lettuce与jedis区别
Lettuce 和 Jedis 的都是连接Redis Server的客户端程序。Jedis在实现上是直连redis server,多线程环境下非线程安全(即多个线程对一个连接实例操作,是线程不安全的),除非使用连接池,为每个Jedis实例增加物理连接。Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问(即多个线程公用一个连接实例,线程安全),同时它是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
原文地址:http://www.cnblogs.com/qq53462202/p/16821750.html