这篇文章将为大家详细讲解有关springboot中怎么配置创建多个redis,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
以下是配置的定义规范:
spring:
redis:
timeout: 1000
lettuce:
pool:
maxActive: 2500
max-wait: 6000
max-idle: 500
min-idle: 100
sentinels:
temp1:
master: a
nodes: ip1:10201,ip2:10202
password:
temp2:
master: b
nodes: ip3:10201,ip4:10202
password:
primary: true //是否主要的bean
配置中其他的redis配置还是遵循springboot官方的,但另外扩展了一个sentinels属性,这个属性填充多个redis 配置信息,由于我们项目主要使用哨兵模式,故这里使用sentinel方式实现。
其次配置类根据上面的配置信息可以定义了:
@ConfigurationProperties(prefix = "spring.redis.sentinels")
public class RedisExtProperties extends HashMap<String, ExtSentinel>{
private static final long serialVersionUID = 856175258267105532L;
public static class ExtSentinel extends Sentinel {
private String password;
private boolean primary;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
}
}
以上是获取配置信息的配置类了,接下来要通过某些手段去生成StringRedisTemplate的bean了,由于有多个bean,而且bean的名称要自己通过配置文件中定义的,通过注解@Bean或者xml等方式貌似都无法达到目的,这里就利用BeanDefinitionRegistryPostProcessor接口去实现,该接口怎么使用可以去查看spring的一些文档或者网上搜索都可以找到,这里不在赘述。
这个接口有两个方法postProcessBeanFactory、postProcessBeanDefinitionRegistry,这两个方法都可以实现动态注册bean,大家也可以去网上搜索,但是呢,这里却不能通过这两个方法去实现动态注册StringRedisTemplate的bean,因为在初始化BeanDefinitionRegistryPostProcessor这个接口的实现时,还并没有完全加载springboot的相关配置,导致在这两个方法里或者通过注解@Autowired都无法把RedisExtProperties注入进来,即便注入进来,也是没有把相关配置信息初始化进去的,这把就坑了,后面想了半天直接通过AutowiredAnnotationBeanPostProcessor这个实现,重写它的postProcessProperties方法去触发动态注册bean。
@Component
public class RedisCustomFactory extends AutowiredAnnotationBeanPostProcessor
implements BeanDefinitionRegistryPostProcessor {
private final Logger logger = LoggerFactory.getLogger(getClass());
BeanDefinitionRegistry registry;
ConfigurableListableBeanFactory factory;
AtomicBoolean open = new AtomicBoolean(false);
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
if (!open.get()) {
processFields(bean, bean.getClass().getDeclaredFields());
}
return super.postProcessProperties(pvs, bean, beanName);
}
private void processFields(Object bean, Field[] declaredFields) {
for (Field field : declaredFields) {
if (!open.get() && field.getType().isAssignableFrom(RedisOperations.class)) {
register(factory.getBean(RedisProperties.class), factory.getBean(RedisExtProperties.class),
factory.getBeanProvider(LettuceClientConfigurationBuilderCustomizer.class));
open.compareAndSet(false, true);
}
}
}
private LettuceClientConfigurationBuilder createBuilder(Pool pool) {
if (pool == null) {
return LettuceClientConfiguration.builder();
}
return new PoolBuilderFactory().createBuilder(pool);
}
// private void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder,
// ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers) {
// builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
// }
private LettuceClientConfigurationBuilder applyProperties(
LettuceClientConfiguration.LettuceClientConfigurationBuilder builder, RedisProperties properties) {
if (properties.isSsl()) {
builder.useSsl();
}
if (properties.getTimeout() != null) {
builder.commandTimeout(properties.getTimeout());
}
if (properties.getLettuce() != null) {
RedisProperties.Lettuce lettuce = properties.getLettuce();
if (lettuce.getShutdownTimeout() != null && !lettuce.getShutdownTimeout().isZero()) {
builder.shutdownTimeout(properties.getLettuce().getShutdownTimeout());
}
}
return builder;
}
private LettuceClientConfiguration getLettuceClientConfiguration(ClientResources clientResources, Pool pool,
RedisProperties properties,
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers) {
LettuceClientConfigurationBuilder builder = createBuilder(pool);
applyProperties(builder, properties);
builder.clientResources(clientResources);
// customize(builder, builderCustomizers);
return builder.build();
}
private List<RedisNode> createSentinels(RedisProperties.Sentinel sentinel) {
List<RedisNode> nodes = new ArrayList<>();
for (String node : sentinel.getNodes()) {
try {
String[] parts = StringUtils.split(node, ":");
Assert.state(parts.length == 2, "Must be defined as 'host:port'");
nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
} catch (RuntimeException ex) {
throw new IllegalStateException("Invalid redis sentinel " + "property '" + node + "'", ex);
}
}
return nodes;
}
protected RedisSentinelConfiguration getSentinelConfig(ExtSentinel sentinelProperties, RedisProperties properties) {
if (sentinelProperties != null) {
RedisSentinelConfiguration config = new RedisSentinelConfiguration();
config.master(sentinelProperties.getMaster());
config.setSentinels(createSentinels(sentinelProperties));
if (sentinelProperties.getPassword() != null) {
config.setPassword(RedisPassword.of(sentinelProperties.getPassword()));
}
config.setDatabase(properties.getDatabase());
return config;
}
return null;
}
private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientConfiguration clientConfiguration,
RedisSentinelConfiguration redisSentinelConfiguration, RedisProperties properties) {
return new LettuceConnectionFactory(redisSentinelConfiguration, clientConfiguration);
}
private LettuceConnectionFactory redisConnectionFactory(ClientResources clientResources,
RedisSentinelConfiguration redisSentinelConfiguration, RedisProperties properties,
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers)
throws UnknownHostException {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources,
properties.getLettuce().getPool(), properties, null);
return createLettuceConnectionFactory(clientConfig, redisSentinelConfiguration, properties);
}
public synchronized void register(RedisProperties properties, RedisExtProperties extProperties,
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers) throws BeansException {
if (extProperties == null) {
return;
}
extProperties.forEach((name, sentinel) -> {
try {
if (!factory.containsBeanDefinition(name + "RedisTemplate")) {
logger.info("{} -----> {}", name, sentinel.isPrimary());
DefaultClientResources res = DefaultClientResources.create();
BeanDefinitionBuilder builder0 = BeanDefinitionBuilder
.genericBeanDefinition(DefaultClientResources.class, () -> res);
BeanDefinition beanDefinition0 = builder0.getRawBeanDefinition();
beanDefinition0.setPrimary(sentinel.isPrimary());
beanDefinition0.setDestroyMethodName("shutdown");
registry.registerBeanDefinition(name + "DefaultClientResources", beanDefinition0);
LettuceConnectionFactory ref = redisConnectionFactory(res, getSentinelConfig(sentinel, properties),
properties, builderCustomizers);
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder
.genericBeanDefinition(RedisConnectionFactory.class, () -> ref);
BeanDefinition beanDefinition1 = builder1.getRawBeanDefinition();
beanDefinition1.setPrimary(sentinel.isPrimary());
registry.registerBeanDefinition(name + "RedisConnectionFactory", beanDefinition1);
BeanDefinitionBuilder builder2 = BeanDefinitionBuilder
.genericBeanDefinition(StringRedisTemplate.class, () -> {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(ref);
return template;
});
BeanDefinition beanDefinition2 = builder2.getRawBeanDefinition();
beanDefinition2.setPrimary(sentinel.isPrimary());
registry.registerBeanDefinition(name + "RedisTemplate", beanDefinition2);
}
} catch (Exception ex) {
logger.error("register redisProperties error", ex);
}
});
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
this.factory = factory;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
}
@Override
public int getOrder() {
return super.getOrder() - 1;
}
}
public class PoolBuilderFactory {
public LettuceClientConfigurationBuilder createBuilder(Pool properties) {
return LettucePoolingClientConfiguration.builder().poolConfig(getPoolConfig(properties));
}
private GenericObjectPoolConfig<?> getPoolConfig(Pool properties) {
GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(properties.getMaxActive());
config.setMaxIdle(properties.getMaxIdle());
config.setMinIdle(properties.getMinIdle());
if (properties.getTimeBetweenEvictionRuns() != null) {
config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());
}
if (properties.getMaxWait() != null) {
config.setMaxWaitMillis(properties.getMaxWait().toMillis());
}
return config;
}
}
根据代码的细节,可以看到sentinels其实是一个map,会把sentinels的key和RedisTemplate拼接成bean的名字,所以在使用的过程中,如果有primary配置的直接使用@Autowired就可以直接注入了,其他的则@Qualifier+@Autowired既可以注入了。
@Autowired
private StringRedisTemplate stringRedisTemplate;//对应的master 为b的
@Autowired
@Qualifier("temp1RedisTemplate")
private StringRedisTemplate microblogRedisTemplate;//对应的master 为a的
关于springboot中怎么配置创建多个redis就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/154652/blog/3084342