Java SpringBoot配置Redis多數據源


前段時間寫一個項目,有一個功能實時性要求比較高,而且讀寫操作也很頻繁,最后決定邏輯層使用Redis支持,當流程結束后再做數據持久化。因為高並發,且該功能數據比較獨立,所以采用了一個單獨的Redis數據源,跟主流程的Redis分開。

這里簡單寫一個SpringBoot配置Redis多數據源的Demo記錄一下。

pom.xml 文件引入Redis依賴:spring-boot-starter-data-redis 線程池:commons-pool2 :

<dependencies>
  ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.9.0</version>
    </dependency>
  ...
</dependencies>

既然是多數據源,就需要配置兩個Redis數據源。在 application.yml 或 application.properties 添加配置,本篇使用 application.yml  文件:

1: 配置一個端口為6379的默認Redis;

2: 配置一個端口為6380的 UserRedis;連接池的配置寫在上面和下面都行,初始化的時候能讀取到就行了

spring:
  redis:
    host: localhost
    port: 6379
    timeout: 3000
    database: 0
# 第二個redis配置 redis-user: # Host host: localhost # 密碼 password: # 端口 port: 6380 # 超時時間 timeout: 3000 # 數據庫 database: 0 # 連接池最大活躍連接數 max-active: 100 # 連接池最大建立連接等待時間, 單位為ms, 如果超過此時間將拋出異常 max-wait: 3000 # 連接池最大空閑連接數, 超過空閑數將被標記為不可用,然后被釋放 max-idle: 20 # 連接池里始終應該保持的最小連接數 min-idle: 0

因為這里擬定第二個Redis數據源是為User邏輯服務的,所以創建一個讀取UserRedis配置類:

UserRedisProperties.java : 

package com.demo.redisdemo.config.redis;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author AnYuan
 */

@Data
@Component
// 配置前綴
@ConfigurationProperties( prefix = "spring.redis-user")
public class UserRedisProperties {

    /**
     * 配置里面的中划線: '-' 轉為駝峰寫法即可讀取配置
     */

    private String host;
    private String password;
    private int port;
    private int timeout;
    private int database;
    private int maxWait;
    private int maxActive;
    private int maxIdle;
    private int minIdle;
}

接下來就是重點,總結來說就是讀取UserRedis的配置,聲明一個 @Bean ,設置好對應的參數,創建第二個RedisTemplate。

創建一個初始化的配置類:RedisConfigure.java :

package com.demo.redisdemo.config.redis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * Redis 初始化配置
 * @author AnYuan
 */

@Configuration
@EnableCaching
public class RedisConfigure extends CachingConfigurerSupport {

    @Autowired
    private UserRedisProperties userRedisProperties;

    /**
     * @Bean:
     * 1: 這里聲明該方法返回的是受Spring容器管理的Bean
     * 2: 方法名與返回類名一致,但首字母小寫:為redisTemplateUser
     */

    @Bean
    public <T> RedisTemplate<String, T> redisTemplateUser() {

        // 基本配置
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(userRedisProperties.getHost());
        configuration.setPort(userRedisProperties.getPort());
        configuration.setDatabase(userRedisProperties.getDatabase());
        if (Strings.isNotBlank(userRedisProperties.getPassword())) {
            configuration.setPassword(RedisPassword.of(userRedisProperties.getPassword()));
        }

        // 連接池配置
        GenericObjectPoolConfig<Object> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
        genericObjectPoolConfig.setMaxTotal(userRedisProperties.getMaxActive());
        genericObjectPoolConfig.setMaxWaitMillis(userRedisProperties.getMaxWait());
        genericObjectPoolConfig.setMaxIdle(userRedisProperties.getMaxIdle());
        genericObjectPoolConfig.setMinIdle(userRedisProperties.getMinIdle());

        // lettuce pool
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
        builder.poolConfig(genericObjectPoolConfig);
        builder.commandTimeout(Duration.ofSeconds(userRedisProperties.getTimeout()));
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, builder.build());

        lettuceConnectionFactory.afterPropertiesSet();
        return createRedisTemplate(lettuceConnectionFactory);
    }

    private <T> RedisTemplate<String, T> createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, T> stringObjectRedisTemplate = new RedisTemplate<>();
        stringObjectRedisTemplate.setConnectionFactory(redisConnectionFactory);

        RedisSerializer<String> redisSerializer = new StringRedisSerializer();

        // key序列化
        stringObjectRedisTemplate.setKeySerializer(redisSerializer);
        // value序列化
        stringObjectRedisTemplate.setValueSerializer(redisSerializer);
        // value hashMap序列化
        stringObjectRedisTemplate.setHashValueSerializer(redisSerializer);
        // key haspMap序列化
        stringObjectRedisTemplate.setHashKeySerializer(redisSerializer);

        return stringObjectRedisTemplate;
    }
}

這個時候啟動SpringBoot應用,Spring的容器里面就管理着一個name為redisTemplateUser的Bean了,也就是通過這個Bean可以使用第二個數據源的Redis。

最后我們做一個單元測試,創建一個測試類:RedisTest.java :

package com.demo.redisdemo.redis;


import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.concurrent.TimeUnit;

@SpringBootTest
public class RedisTest {

    /**
     * 當一個接口有多個實現類的時候
     * 將 @Qualifier 注解與我們想要使用的 Spring Bean 名稱一起進行裝配
     * Spring 框架就能從多個相同類型並滿足裝配要求的 Bean 中找到我們想要的
     *
     * 這里綁定初始化里面注入的Bean:redisTemplateUser
     */

    /**
     * 第二個數據源的配置並指定String數據類型 UserRedis
     */
    @Autowired
    @Qualifier("redisTemplateUser")
    private RedisTemplate<String, String> redisTemplateUser;

    /**
     * 默認數據源配置並指定String數據類型的Redis
     */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 默認數據源配置的String數據類型的Redis
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    

    @Test
    public void redisTest() {
        System.out.println("----------Start----------");

        // 端口6380的Redis
        redisTemplateUser.opsForValue().set("redisTemplateUser", "success", 1, TimeUnit.DAYS);

        // 端口6379默認Redis
        redisTemplate.opsForValue().set("redisTemplate", "success", 1, TimeUnit.DAYS);

        // 端口6379並指定String數據類型的默認Redis
        stringRedisTemplate.opsForValue().set("stringRedisTemplate", "success", 1, TimeUnit.DAYS);

        System.out.println("----------End----------");

    }
}

最后開啟兩個Redis,當前無數據:

 運行測試用例后,再查看Redis的緩存情況:

整個過程比較簡單,就是引入擴展包,配置多數據源,讀取數據源,初始化Bean,最后就可以直接使用了。需要注意的是:因為Redis有默認的實現類了,所以在裝配使用的時候,要加上@Qualifier注解並指定前面Bean注入的名字,不然自動注入后會使用默認的配置,不能使用指定的Redis數據源。

 

本篇代碼Github:https://github.com/Journeyerr/cnblogs/tree/master/redisDemo

Redis擴展包https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis

線程池擴展包:https://mvnrepository.com/artifact/org.apache.commons/commons-pool2

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM