spring boot整合Redis

spring boot整合Redis

spring boot与各个中间件的组合在其官方文档上面都有,,这里介绍下两种连接Redis的方式:Jedis、Lettuce。
本次spring boot版本是基于目前的最新版本:2.1.1.RELEASE。

1. 引入相关starter

pom.xml里面添加如下依赖


	org.springframework.boot
	spring-boot-starter-data-redis

2.Redis配置

配置连接参数

#redis基础配置
spring.redis.database=1
spring.redis.host=xxx
spring.redis.password=
spring.redis.port=6380
spring.redis.timeout=1000

这些参数基本上就能够连接上redis了。

3.使用

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命令。具体的结果这里就不展示了。

3.spring boot加载redis的原理

spring 可以通过两种方式连接redis,一种是jedis,一种是lettuce。通过debug我们发现spring boot默认注入的连接是LettuceConnectionFactory。

spring boot整合Redis_第1张图片
为啥spring boot默认注入的是LettuceConnectionFactory而不是JedisConnectionFactory呢?
在idea工程的external libraries找到spring-boot-autoconfigure包,打开data -> redis
spring boot整合Redis_第2张图片
这里有两个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看看是否如此:
spring boot整合Redis_第3张图片
我们看到connectionFactory被替换为了JedisConnectionFactory。

4.lettuce和jedis对比

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有如下几种情况你不能在线程之间复用连接:

  1. 请求批量下发,即禁止调用命令后立即flush
  2. 使用BLPOP这种阻塞命令
  3. 事务操作
  4. 有多个数据库的情况

所以LettuceConnectionFactory只有在使用阻塞命令或者事务操作的时候才会使用到连接池。

NOTE:

  1. 在pom.xml加入依赖spring-boot-starter-data-redis
  2. 在配置文件中配置相关参数
  3. spring boot有两种连接redis的方式一种是:jedis;一种是lettuce
  4. spring boot默认使用lettuce连接redis
  5. 如果使用 Jedis 替代 Lettuce 则需要排除lettuce,并引入jedis
  6. 要使用连接池的时候需要引入commons-pool2

PS:完整的代码在:https://github.com/Json-Lin/spring-boot-practice/tree/master/spring-boot-practice-redis

END.

你可能感兴趣的:(spring-boot)