spring boot与各个中间件的组合在其官方文档上面都有,,这里介绍下两种连接Redis的方式:Jedis、Lettuce。
本次spring boot版本是基于目前的最新版本:2.1.1.RELEASE。
pom.xml里面添加如下依赖
org.springframework.boot
spring-boot-starter-data-redis
配置连接参数
#redis基础配置
spring.redis.database=1
spring.redis.host=xxx
spring.redis.password=
spring.redis.port=6380
spring.redis.timeout=1000
这些参数基本上就能够连接上redis了。
spring-data-redis可以通过注入StringRedisTemplate和RedisTemplate两种方式操作redis。StringRedisTemplate继承自RedisTemplate是对string类型的key-vale的特殊处理类。下面测试两个基本的方法。
@Service
public class RedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void lpush(String key, String value) {
stringRedisTemplate.opsForList().leftPush(key, value);
}
public void lpop(String key) {
stringRedisTemplate.opsForList().leftPop(key);
}
}
opsForList()表明这个操作是针对list类型的。其它的还有针对set、hash等操作。获得ListOperations后通过ListOperations执行相关的redis命令,一个lpush和lpop命令。具体的结果这里就不展示了。
spring 可以通过两种方式连接redis,一种是jedis,一种是lettuce。通过debug我们发现spring boot默认注入的连接是LettuceConnectionFactory。
为啥spring boot默认注入的是LettuceConnectionFactory而不是JedisConnectionFactory呢?
在idea工程的external libraries找到spring-boot-autoconfigure包,打开data -> redis
这里有两个configuration:JedisConnectionConfiguration和LettuceConnectionConfiguration。spring boot就是通过这两个类来自动配置redis。LettuceConnectionConfiguration的部分代码如下
@Configuration
@ConditionalOnClass(RedisClient.class)
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
......
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public LettuceConnectionFactory redisConnectionFactory(
ClientResources clientResources) throws UnknownHostException {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(
clientResources, this.properties.getLettuce().getPool());
return createLettuceConnectionFactory(clientConfig);
}
@ConditionalOnClass注解是spring boot实现自动化配置的主要注解之一。其作用大概是当xxx.class在类加载路径下时@Configuration生效。所有当我们引入spring-boot-starter-data-redis后RedisClient.class也被引入了,此时spring就会初始化LettuceConnectionConfiguration 。
@ConditionalOnMissingBean(RedisConnectionFactory.class)原理类似,当spring容器没有RedisConnectionFactory bean的时候注入一个LettuceConnectionFactory。
接下来看看JedisConnectionFactory。
JedisConnectionFactory的部分代码如下:
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
......
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
return createJedisConnectionFactory();
}
可以看到JedisConnectionFactory的注入条件更多,需要类路径下同时存在 GenericObjectPool.class, JedisConnection.class, Jedis.class时才会注入JedisConnectionFactory。
通过以上的分析,当我们只在pom.xml里面引入spring-boot-starter-data-redis时JedisConnectionConfiguration 需要的@ConditionalOnClass条件不满足,所以spring boot默认注入的是LettuceConnectionFactory。
下面我们更改下pom.xml的代码如下:
org.springframework.boot
spring-boot-starter-data-redis
io.lettuce
lettuce-core
org.apache.commons
commons-pool2
2.6.0
redis.clients
jedis
在这里我们排除了lettuce相关的包,并引入jedis。其中GenericObjectPool.class存在于commons-pool2包里面(jiedis自带commons-pool2,commons-pool2在这里有介绍过), Jedis.class 在jedis包里面。这样就满足了JedisConnectionConfiguration 的条件。再次debug看看是否如此:
我们看到connectionFactory被替换为了JedisConnectionFactory。
jedis:是Redis的Java实现客户端,提供了比较全面的Redis命令的支持。
lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
Jedis 在实现上是直接连接 Redis-Server,在多个线程间共享一个 Jedis 实例时是线程不安全的,如果想要在多线程场景下使用 Jedis,需要使用连接池(此点可以从JedisConnectionConfiguration 中GenericObjectPool.class是必要条件之一可以看出)来管理连接,而不是每次都生成一个新的连接。
与 Jedis 相比,Lettuce 则完全克服了其线程不安全的缺点:Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型。
Lettuce 和Redis的连接池配置如下:
#redis lettuce连接池配置 使用的common-pool2的连接池
#shutdown的超时时间
#spring.redis.lettuce.shutdown-timeout=100ms
#连接池最大活跃连接数
#spring.redis.lettuce.pool.max-active=8
#连接池最大空闲连接数
#spring.redis.lettuce.pool.max-idle=8
#当连接池达到最大连接数时,等待可用的连接的等待时间
#spring.redis.lettuce.pool.max-wait=-1ms
#连接池最小空闲连接数
#spring.redis.lettuce.pool.min-idle=0
#redis jedis连接配置
#spring.redis.jedis.pool.max-active=8
#spring.redis.jedis.pool.max-idle=8
#spring.redis.jedis.pool.max-wait=-1ms
#spring.redis.jedis.pool.min-idle=0
连接池使用的是commons-pool2(commons-pool2在这里有介绍过)
lettuce既然是线程安全的那为什么也有连接池的配置呢?
lettuce有如下几种情况你不能在线程之间复用连接:
BLPOP
这种阻塞命令所以LettuceConnectionFactory只有在使用阻塞命令或者事务操作的时候才会使用到连接池。
NOTE:
PS:完整的代码在:https://github.com/Json-Lin/spring-boot-practice/tree/master/spring-boot-practice-redis
END.