Spring工程中集成多个redis数据源
问题
有个项目需要在同一个Spring工程中集成2个redis数据源。
思路
配置2个redis连接工厂,再配置2个redistemplate。然后,在使用缓存的时候,分别注入不同的redistemplate解决这个问题。这里主要是使用了spring中的2个注释:
@Primary
:设置默认bean@Qualifier
:指定注入bean
解决
FhRedisConfig.java
这个类是配置第2个多余的redis,对application.yml文件中自定义redis配置映射类。如果application.yml文件中有如下配置:
fh:redis:host: 12.86.12.9password: swdghopport: 6379database:7
这对应配置类如下:
package com.xxxx.framework.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** redis配置类*/
@Data
@ConfigurationProperties(prefix = "fh.redis")
public class FhRedisConfig {/*** 主机地址*/private String host;/*** 密码*/private String password;/*** Redis 服务器端口号* 默认值:6379(Redis 默认端口)*/private int port = 6381;/*** Redis 数据库索引(0-15)* 默认值:0*/private int database = 0;}
RedisConfig.java
这是redis配置类,这里主要配置2个redis连接工厂,2个redistemplate的bean。而且,使用@Primary
设置redistemplate类注入的默认bean为哪个redistemplate的bean。而且,如果增加了对redis集群配置的支持。
package com.xxxx.framework.config;import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
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.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.CollectionUtils;import javax.annotation.Resource;
import java.util.List;/*** redis配置* */
@Configuration
@EnableCaching
@EnableConfigurationProperties(FhRedisConfig.class)
public class RedisConfig extends CachingConfigurerSupport
{@Resourceprivate FhRedisConfig fhRedisConfig;@Value("${spring.profiles.active:default}")private String activeProfile;/*** 默认redis连接池* @return 默认redis连接池*/@Bean@Primarypublic RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {// 从 RedisProperties 提取连接池配置(如果存在)return getRedisConnectionFactory(redisProperties, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getPassword(),redisProperties.getDatabase(), redisProperties.getCluster() == null ? null : redisProperties.getCluster().getNodes());}/*** redis连接池* @return redis连接池*/@Beanpublic RedisConnectionFactory fhRedisConnectionFactory(RedisProperties redisProperties) {return getRedisConnectionFactory(redisProperties, fhRedisConfig.getHost(), fhRedisConfig.getPort(), fhRedisConfig.getPassword(),fhRedisConfig.getDatabase(), null);}/*** redis客户端* @param connectionFactory redis连接池* @return redis客户端*/@Beanpublic RedisTemplate<Object, Object> fhRedisTemplate(@Qualifier("fhRedisConnectionFactory")RedisConnectionFactory connectionFactory){return getRedisTemplate(connectionFactory);}/*** 默认redis客户端* @param connectionFactory 默认redis连接池* @return 默认redis客户端*/@Bean@Primarypublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){return getRedisTemplate(connectionFactory);}private static RedisTemplate<Object, Object> getRedisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJson2JsonRedisSerializer<Object> serializer = new FastJson2JsonRedisSerializer<>(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}private RedisConnectionFactory getRedisConnectionFactory(RedisProperties redisProperties, String host, int port, String password, int database, List<String> nodes) {LettuceConnectionFactory lettuceConnectionFactory;// 根据是否是集群模式选择不同的配置if (!CollectionUtils.isEmpty(nodes)) {// 配置集群拓扑刷新选项ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder().refreshPeriod(redisProperties.getLettuce().getCluster().getRefresh().getPeriod()).enableAdaptiveRefreshTrigger(ClusterTopologyRefreshOptions.RefreshTrigger.MOVED_REDIRECT,ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS).build();ClusterClientOptions clientOptions = ClusterClientOptions.builder().topologyRefreshOptions(refreshOptions).build();GenericObjectPoolConfig<?> poolConfig = getGenericObjectPoolConfig(redisProperties);LettucePoolingClientConfiguration.LettucePoolingSslClientConfigurationBuilder lettucePoolingSslClientConfigurationBuilder = LettucePoolingClientConfiguration.builder().clientOptions(clientOptions).poolConfig(poolConfig) // 关键:设置连接池.commandTimeout(redisProperties.getTimeout()).useSsl();if (!activeProfile.equals("prod")) {lettucePoolingSslClientConfigurationBuilder.disablePeerVerification();}LettucePoolingClientConfiguration poolingClientConfig = lettucePoolingSslClientConfigurationBuilder.build();// 创建集群配置RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(nodes);clusterConfig.setPassword(password);// 创建 LettuceConnectionFactorylettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, poolingClientConfig);} else {// 非集群模式保持原逻辑GenericObjectPoolConfig<?> poolConfig = getGenericObjectPoolConfig(redisProperties);LettucePoolingClientConfiguration.LettucePoolingSslClientConfigurationBuilder lettucePoolingSslClientConfigurationBuilder = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig) // 关键:设置连接池.commandTimeout(redisProperties.getTimeout()).useSsl();if (!activeProfile.equals("prod")) {lettucePoolingSslClientConfigurationBuilder.disablePeerVerification();}RedisStaticMasterReplicaConfiguration serverConfig = new RedisStaticMasterReplicaConfiguration(host, port);serverConfig.setPassword(password);LettucePoolingClientConfiguration poolingClientConfig = lettucePoolingSslClientConfigurationBuilder.build();lettuceConnectionFactory = new LettuceConnectionFactory(serverConfig, poolingClientConfig);}lettuceConnectionFactory.setDatabase(database);return lettuceConnectionFactory;}private static GenericObjectPoolConfig<?> getGenericObjectPoolConfig(RedisProperties redisProperties) {GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();if (redisProperties.getLettuce().getPool() != null) {RedisProperties.Pool poolProps = redisProperties.getLettuce().getPool();poolConfig.setMaxTotal(poolProps.getMaxActive()); // max-activepoolConfig.setMaxIdle(poolProps.getMaxIdle()); // max-idlepoolConfig.setMinIdle(poolProps.getMinIdle()); // min-idlepoolConfig.setMaxWaitMillis(poolProps.getMaxWait().toMillis()); // max-wait}return poolConfig;}
}
注意@Qualifier
注释的使用,这里使用指定了特定的redis连接工厂。下面的在业务代码中注入redistemaplte的时候,也需要使用呢@Qualifier
注释来使用特定的redis集群。
Controller.java
这是业务代码中,注入使用特定的redis集群,如下代码:
@Resource
@Qualifier("fhRedisTemplate")
private RedisTemplate<String, Integer> fhRedisTemplate;
如果不需要使用特定redis,只需要使用默认redis则不需要@Qualifier
注释,如下:
@Resource
public RedisTemplate redisTemplate;
总结
这就是Spring项目redis多数据源问题。主要就是通过@Primary
注释来配置默认bean,通过@Qualifier
注释来指定使用的bean。
参考
- Multiple Redis Connections in Spring Boot
- Spring Boot Redis CRUD Example
- The Spring @Qualifier Annotation
- Connection Modes
- 【Redis】Integration with Spring Boot
- Accessing AWS ElastiCache (Redis) from different Amazon VPC(s) via AWS PrivateLink