springboot系列文章之 集成redis 服务 (Lettuce & Jedis)

原文博客地址: pjmike的博客html

前言

在实际项目开发过程当中,相信不少人都有用到过 redis 这个NoSQL,这篇文章就详细讲讲springboot如何整合 redisjava

Redis 简介

简单介绍下Redis:git

Redis是一个开源的使用 ANSI C语言编写,支持网络,可基于内存也可持久化的日志型,Key-Value数据库,并提供了多种语言的 API ,相比 Memcached 它支持存储的类型相对更多 (字符,哈希,集合,有序集合,列表等),同时Redis是线程安全的。github

Redis 链接池简介

在后面 springboot 整合 redis 的时候会用到链接池,因此这里先来介绍下 Redis中的链接池:web

客户端链接 Redis 使用的是 TCP协议,直连的方式每次须要创建 TCP链接,而链接池的方式是能够预先初始化好客户端链接,因此每次只须要从 链接池借用便可,而借用和归还操做是在本地进行的,只有少许的并发同步开销,远远小于新建TCP链接的开销。另外,直连的方式没法限制 redis客户端对象的个数,在极端状况下可能会形成链接泄漏,而链接池的形式能够有效的保护和控制资源的使用。redis

下面以Jedis客户端为例,再来总结下 客户端直连方式和链接池方式的对比spring

优势 缺点
直连 简单方便,适用于少许长期链接的场景 1. 存在每次新建/关闭TCP链接开销 2. 资源没法控制,极端状况下出现链接泄漏 3. Jedis对象线程不安全(Lettuce对象是线程安全的)
链接池 1. 无需每次链接生成Jedis对象,下降开销 2. 使用链接池的形式保护和控制资源的使用 相对于直连,使用更加麻烦,尤为在资源的管理上须要不少参数来保证,一旦规划不合理也会出现问题

Jedis vs Lettuce

redis官方提供的java client有如图所示几种: sql

redis
比较突出的是 Lettuce 和 jedis。Lettuce 和 jedis 的都是链接 Redis Server的客户端,Jedis 在实现上是直连 redis server,多线程环境下非线程安全,除非使用链接池,为每一个 redis实例增长 物理链接。

Lettuce 是 一种可伸缩,线程安全,彻底非阻塞的Redis客户端,多个线程能够共享一个RedisConnection,它利用Netty NIO 框架来高效地管理多个链接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。数据库

在 springboot 1.5.x版本的默认的Redis客户端是 Jedis实现的,springboot 2.x版本中默认客户端是用 lettuce实现的。segmentfault

下面介绍 springboot 2.0分别使用 jedislettuce集成 redis服务

springboot 2.0 经过 lettuce集成Redis服务

导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
复制代码

application.properties配置文件

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
# 链接池最大链接数(使用负值表示没有限制) 默认为8
spring.redis.lettuce.pool.max-active=8
# 链接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.lettuce.pool.max-wait=-1ms
# 链接池中的最大空闲链接 默认为8
spring.redis.lettuce.pool.max-idle=8
# 链接池中的最小空闲链接 默认为 0
spring.redis.lettuce.pool.min-idle=0
复制代码

自定义 RedisTemplate

默认状况下的模板只能支持 RedisTemplate<String,String>,只能存入字符串,不少时候,咱们须要自定义 RedisTemplate ,设置序列化器,这样咱们能够很方便的操做实例对象。以下所示:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}
复制代码

定义测试实体类

public class User implements Serializable {
    private static final long serialVersionUID = 4220515347228129741L;
    private Integer id;
    private String username;
    private Integer age;

    public User(Integer id, String username, Integer age) {
        this.id = id;
        this.username = username;
        this.age = age;
    }

    public User() {
    }
    //getter/setter 省略
}
复制代码

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
    private Logger logger = LoggerFactory.getLogger(RedisTest.class);
    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;

    @Test
    public void test() {
        String key = "user:1";
        redisTemplate.opsForValue().set(key, new User(1,"pjmike",20));
        User user = (User) redisTemplate.opsForValue().get(key);
        logger.info("uesr: "+user.toString());
    }
}
复制代码

springboot 2.0 经过 jedis 集成Redis服务

导入依赖

由于 springboot2.0中默认是使用 Lettuce来集成Redis服务,spring-boot-starter-data-redis默认只引入了 Lettuce包,并无引入 jedis包支持。因此在咱们须要手动引入 jedis的包,并排除掉 lettuce的包,pom.xml配置以下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
复制代码

application.properties配置

使用jedis的链接池

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-active=8
复制代码

配置 JedisConnectionFactory

由于在 springoot 2.x版本中,默认采用的是 Lettuce实现的,因此没法初始化出 Jedis的链接对象 JedisConnectionFactory,因此咱们须要手动配置并注入

public class RedisConfig {
    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        return factory;
    }
复制代码

可是启动项目后发现报出了以下的异常:

jedis_error

redis链接失败,springboot2.x经过以上方式集成Redis并不会读取配置文件中的 spring.redis.host等这样的配置,须要手动配置,以下:

@Configuration
public class RedisConfig2 {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.password}")
    private String password;
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(JedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }
    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(port);
        config.setPassword(RedisPassword.of(password));
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(config);
        return connectionFactory;
    }
}
复制代码

经过以上方式就能够链接上 redis了,不过这里要提醒的一点就是,在springboot 2.x版本中 JedisConnectionFactory设置链接的方法已过期,如图所示:

jedis_timeout

springboot 2.x版本中推荐使用 RedisStandaloneConfiguration类来设置链接的端口,地址等属性

而后是单元测试,与上面 Lettuce的例子代码同样,而且测试经过。

小结

上面介绍springboot 2.x版本如何经过 Jedis 和 Lettuce 来集成Redis服务,源代码地址以下:github.com/pjmike/spri…

参考资料 & 鸣谢

相关文章
相关标签/搜索