这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
背景
在微服务概念中,不同的服务需要使用不同的数据库,包括mysql与redis,但是如果是需要高并发又与这样设计造成冲突,因为直接查询redis会更快一些。
集成Redis多数据源与lettuce连接池
springboot中集成redis多个数据源需要屏蔽starter中带有的原生RedisAutoConfiguration。
并模拟RedisAutoConfiguration,设置多个redisTemplate的bean。并在使用时通过Autowired+Qualifier注入。
依赖添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
yaml文件中配置多数据源连接信息,配置一个端口为6379的默认Redis1和一个端口为6380的Redis2
redis:
lettuce1:
host: localhost
password:
port: 6379
timeout: 5000
pool:
maxWaitMillis: 10000
minIdle: 5
maxIdle: 160
maxTotal: 500
lettuce2:
host: localhost
password:
port: 6380
timeout: 5000
pool:
maxWaitMillis: 10000
minIdle: 5
maxIdle: 160
maxTotal: 500
排除RedisAutoConfiguration
不使用默认的springboot进行加载初始化,必须要在注解中排除RedisAutoConfiguration
@Import(value = {
RedisLettuceConfig1.class,
RedisLettuceConfig2.class
})
@SpringBootApplication(exclude = {
RedisAutoConfiguration.class
})
Redis1配置类
配置lettuce连接池、数据源、数据源的连接工厂、RedisTemplate。并设置序列化方式
@EnableConfigurationProperties({RedisLettuceProperties1.class})
public class RedisLettuceConfig1 {
private static final String REDIS_STANDALONE_CONFIGURATION = "redisStandaloneConfiguration1";
private static final String LETTUCE_CLIENT_CONFIGURATION = "lettuceClientConfiguration1";
public static final String REDIS_CONNECTION_FACTORY = "redisLettuceConnectionFactory1";
public static final String REDIS_TEMPLATE = "redisLettuceTemplate1";
@Autowired
private RedisLettuceProperties1 redisProperties;
public RedisLettuceConfig1() {
}
@Bean(
name = {"redisStandaloneConfiguration1"}
)
public RedisStandaloneConfiguration redisStandaloneConfiguration() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(this.redisProperties.getHost(), this.redisProperties.getPort());
if (!StringUtils.isEmpty(this.redisProperties.getPassword())) {
RedisPassword password = RedisPassword.of(this.redisProperties.getPassword());
configuration.setPassword(password);
}
configuration.setDatabase(this.redisProperties.getDbIndex());
return configuration;
}
@Bean(
name = {"lettuceClientConfiguration1"}
)
public LettuceClientConfiguration lettuceClientConfiguration() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMinIdle(this.redisProperties.getPool().getMinIdle());
config.setMaxIdle(this.redisProperties.getPool().getMaxIdle());
config.setMaxTotal(this.redisProperties.getPool().getMaxTotal());
config.setMaxWaitMillis((long)this.redisProperties.getPool().getMaxWaitMillis());
config.setTestOnBorrow(this.redisProperties.getPool().getTestOnBorrow());
config.setTestOnReturn(this.redisProperties.getPool().getTestOnReturn());
LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(config).commandTimeout(Duration.ofMillis((long)this.redisProperties.getTimeout())).build();
return configuration;
}
@Bean(
name = {"redisLettuceConnectionFactory1"}
)
public RedisConnectionFactory redisConnectionFactory(@Qualifier("redisStandaloneConfiguration1") RedisStandaloneConfiguration redisStandaloneConfiguration, @Qualifier("lettuceClientConfiguration1") LettuceClientConfiguration lettuceClientConfiguration) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
return factory;
}
@Bean(
name = {"redisLettuceTemplate1"}
)
public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisLettuceConnectionFactory1") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
RedisSerializer<Object> objectSerializer = new JdkSerializationRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(objectSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(objectSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
Redis2配置类
@EnableConfigurationProperties({RedisLettuceProperties2.class})
public class RedisLettuceConfig2 {
private static final String REDIS_STANDALONE_CONFIGURATION = "redisStandaloneConfiguration2";
private static final String LETTUCE_CLIENT_CONFIGURATION = "lettuceClientConfiguration2";
public static final String REDIS_CONNECTION_FACTORY = "redisLettuceConnectionFactory2";
public static final String REDIS_TEMPLATE = "redisLettuceTemplate2";
@Autowired
private RedisLettuceProperties2 RedisLettuceProperties;
public RedisLettuceConfig2() {
}
@Bean(
name = {"redisStandaloneConfiguration2"}
)
public RedisStandaloneConfiguration redisStandaloneConfiguration() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(this.RedisLettuceProperties.getHost(), this.RedisLettuceProperties.getPort());
if (!StringUtils.isEmpty(this.RedisLettuceProperties.getPassword())) {
RedisPassword password = RedisPassword.of(this.RedisLettuceProperties.getPassword());
configuration.setPassword(password);
}
configuration.setDatabase(this.RedisLettuceProperties.getDbIndex());
return configuration;
}
@Bean(
name = {"lettuceClientConfiguration2"}
)
public LettuceClientConfiguration lettuceClientConfiguration() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMinIdle(this.RedisLettuceProperties.getPool().getMinIdle());
config.setMaxIdle(this.RedisLettuceProperties.getPool().getMaxIdle());
config.setMaxTotal(this.RedisLettuceProperties.getPool().getMaxTotal());
config.setMaxWaitMillis((long)this.RedisLettuceProperties.getPool().getMaxWaitMillis());
config.setTestOnBorrow(this.RedisLettuceProperties.getPool().getTestOnBorrow());
config.setTestOnReturn(this.RedisLettuceProperties.getPool().getTestOnReturn());
LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(config).commandTimeout(Duration.ofMillis((long)this.RedisLettuceProperties.getTimeout())).build();
return configuration;
}
@Bean(
name = {"redisLettuceConnectionFactory2"}
)
public RedisConnectionFactory redisConnectionFactory(@Qualifier("redisStandaloneConfiguration2") RedisStandaloneConfiguration redisStandaloneConfiguration, @Qualifier("lettuceClientConfiguration2") LettuceClientConfiguration lettuceClientConfiguration) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
return factory;
}
@Bean(
name = {"redisLettuceTemplate2"}
)
public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisLettuceConnectionFactory2") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
RedisSerializer<Object> objectSerializer = new JdkSerializationRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(objectSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(objectSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
测试
引用redisTemplate并指定来自哪个bean
@Autowired
@Qualifier(RedisLettuceConfig1.REDIS_TEMPLATE)
private RedisTemplate redisTemplate;
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
String value = hashOperations.get("users", userId);
小结
springboot配置redis多数据源的过程比较简单,引入依赖包,添加配置,初始化Bean。
需要注意的是Redis有默认的实现类了,所以在装配使用的时候,要加上@Qualifier注解并指定前面Bean注入的名字,不然自动注入后会使用默认的配置,不能使用指定的Redis数据源。