Java SpringBoot配置Redis多数据源
前段时间写一个项目,有一个功能实时性要求比较高,而且读写操作也很频繁,最后决定逻辑层使用 Redis 支持,当流程结束后再做数据持久化。因为高并发,且该功能数据比较独立,所以采用了一个单独的 Redis 数据源,跟主流程的 Redis 分开。
这里简单写一个 SpringBoot 配置 Redis 多数据源的 Demo 记录一下。
pom.xml 文件引入 Redis 依赖:spring-boot-starter-data-redis 、线程池:commons-pool2 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <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;连接池的配置写在上面和下面都行,初始化的时候能读取到就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | spring: redis: host: localhost port: 6379 timeout: 3000 database: 0 <br> # 第二个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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 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
__EOF__