前段時間寫一個項目,有一個功能實時性要求比較高,而且讀寫操作也很頻繁,最后決定邏輯層使用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
