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…

參考資料 & 鳴謝

相關文章
相關標籤/搜索