redis 在 spring容器的核心类
- StringRedisTemplate 和 RedisTemplate
- 客户端工厂 LettuceConnectionFactory 也可以使用 JedisConnectionFactory
配置文件
redis:
base:
host: 192.168.8.165
port: 6379
database: 0
timeout: 3000
lettuce:
pool:
min-idle: 5
max-idle: 10
max-active: 8
max-wait: 1ms
report:
host: cache164.e6xayf.com
port: 6379
database: 12
timeout: 3000
lettuce:
pool:
min-idle: 5
max-idle: 10
max-active: 8
max-wait: 1ms
配置类
参照 RedisAutoConfiguration 和 LettuceConnectionConfiguration
package com.alibaba.project.config;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* @author demon
* @date 2021/3/1 11:08
*/
@Configuration
@ConfigurationProperties(prefix = "redis")
public class RedisConfig {
private RedisProperties base;
private RedisProperties report;
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(ClientResources.class)
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean(name = "baseStringRedisTemplate")
@Primary
public StringRedisTemplate baseStringRedisTemplate(
@Qualifier("baseLettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean(name = "baseLettuceConnectionFactory")
@Primary
public LettuceConnectionFactory baseLettuceConnectionFactory(ClientResources clientResources) {
RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(base);
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, base);
return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
}
@Bean(name = "reportStringRedisTemplate")
public StringRedisTemplate reportStringRedisTemplate(
@Qualifier("reportLettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean(name = "reportLettuceConnectionFactory")
public LettuceConnectionFactory reportLettuceConnectionFactory(ClientResources clientResources) {
RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(report);
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, report);
return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
}
/**
* redis standalone config
*
* @param redisProperties redis 配置参数
* @return RedisStandaloneConfiguration
*/
private RedisStandaloneConfiguration getStandaloneConfig(RedisProperties redisProperties) {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(redisProperties.getHost());
config.setPort(redisProperties.getPort());
config.setPassword(RedisPassword.of(redisProperties.getPassword()));
config.setDatabase(redisProperties.getDatabase());
return config;
}
/**
* 构建 LettuceClientConfiguration
*
* @param clientResources clientResources
* @param redisProperties redisProperties
* @return LettuceClientConfiguration
*/
private LettuceClientConfiguration getLettuceClientConfiguration(ClientResources clientResources,
RedisProperties redisProperties) {
LettuceClientConfiguration.LettuceClientConfigurationBuilder builder =
createBuilder(redisProperties.getLettuce().getPool());
if (redisProperties.isSsl()) {
builder.useSsl();
}
if (redisProperties.getTimeout() != null) {
builder.commandTimeout(redisProperties.getTimeout());
}
if (redisProperties.getLettuce() != null) {
RedisProperties.Lettuce lettuce = redisProperties.getLettuce();
if (lettuce.getShutdownTimeout() != null
&& !lettuce.getShutdownTimeout().isZero()) {
builder.shutdownTimeout(
redisProperties.getLettuce().getShutdownTimeout());
}
}
builder.clientResources(clientResources);
return builder.build();
}
/**
* 创建 LettuceClientConfigurationBuilder
*
* @param pool 连接池配置
* @return LettuceClientConfigurationBuilder
*/
private LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) {
if (pool == null) {
return LettuceClientConfiguration.builder();
}
return LettucePoolingClientConfiguration.builder()
.poolConfig(getPoolConfig(pool));
}
/**
* pool config
*
* @param properties redis 参数配置
* @return GenericObjectPoolConfig
*/
private GenericObjectPoolConfig getPoolConfig(RedisProperties.Pool properties) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(properties.getMaxActive());
config.setMaxIdle(properties.getMaxIdle());
config.setMinIdle(properties.getMinIdle());
if (properties.getMaxWait() != null) {
config.setMaxWaitMillis(properties.getMaxWait().toMillis());
}
return config;
}
public RedisProperties getBase() {
return base;
}
public void setBase(RedisProperties base) {
this.base = base;
}
public RedisProperties getReport() {
return report;
}
public void setReport(RedisProperties report) {
this.report = report;
}
}
使用
使用 Qualifier 注解指定 StringRedisTemplate 完成注入
优化
上面如果在加一个redis 配置,还需要修改redis 配置类,这是不优雅的。我们可以通过配置文件指定一个 primary 的redis 数据源,其他通过名称+StringRedisTemplate 的方式注入。只增加配置文件,不修改代码,完成注入。这才是比较优雅的解决方案。
注入时,我们通过 beanFactory 以编程的方式注入,这就不会存在硬编码。
public synchronized void setCosBean(String beanName, Class<?> clazz, ConstructorArgumentValues original) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
if (beanFactory.containsBean(beanName)) {
return;
}
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(clazz);
if(beanName.startsWith(primaryKey)){
definition.setPrimary(true);
}
//属性赋值
definition.setConstructorArgumentValues(new ConstructorArgumentValues(original));
//注册到spring上下文
beanFactory.registerBeanDefinition(beanName, definition);
}