溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

springboot中怎么配置創(chuàng)建多個(gè)redis

發(fā)布時(shí)間:2021-06-22 15:28:28 來(lái)源:億速云 閱讀:629 作者:Leah 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)springboot中怎么配置創(chuàng)建多個(gè)redis,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

以下是配置的定義規(guī)范:

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官方的,但另外擴(kuò)展了一個(gè)sentinels屬性,這個(gè)屬性填充多個(gè)redis 配置信息,由于我們項(xiàng)目主要使用哨兵模式,故這里使用sentinel方式實(shí)現(xiàn)。

其次配置類根據(jù)上面的配置信息可以定義了:

@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;
		}

	}
}

以上是獲取配置信息的配置類了,接下來(lái)要通過(guò)某些手段去生成StringRedisTemplate的bean了,由于有多個(gè)bean,而且bean的名稱要自己通過(guò)配置文件中定義的,通過(guò)注解@Bean或者xml等方式貌似都無(wú)法達(dá)到目的,這里就利用BeanDefinitionRegistryPostProcessor接口去實(shí)現(xiàn),該接口怎么使用可以去查看spring的一些文檔或者網(wǎng)上搜索都可以找到,這里不在贅述。

這個(gè)接口有兩個(gè)方法postProcessBeanFactory、postProcessBeanDefinitionRegistry,這兩個(gè)方法都可以實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)bean,大家也可以去網(wǎng)上搜索,但是呢,這里卻不能通過(guò)這兩個(gè)方法去實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)StringRedisTemplate的bean,因?yàn)樵诔跏蓟疊eanDefinitionRegistryPostProcessor這個(gè)接口的實(shí)現(xiàn)時(shí),還并沒(méi)有完全加載springboot的相關(guān)配置,導(dǎo)致在這兩個(gè)方法里或者通過(guò)注解@Autowired都無(wú)法把RedisExtProperties注入進(jìn)來(lái),即便注入進(jìn)來(lái),也是沒(méi)有把相關(guān)配置信息初始化進(jìn)去的,這把就坑了,后面想了半天直接通過(guò)AutowiredAnnotationBeanPostProcessor這個(gè)實(shí)現(xiàn),重寫它的postProcessProperties方法去觸發(fā)動(dòng)態(tài)注冊(cè)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;
	}

}

根據(jù)代碼的細(xì)節(jié),可以看到sentinels其實(shí)是一個(gè)map,會(huì)把sentinels的key和RedisTemplate拼接成bean的名字,所以在使用的過(guò)程中,如果有primary配置的直接使用@Autowired就可以直接注入了,其他的則@Qualifier+@Autowired既可以注入了。

    @Autowired
	private StringRedisTemplate stringRedisTemplate;//對(duì)應(yīng)的master 為b的

	@Autowired
	@Qualifier("temp1RedisTemplate")
	private StringRedisTemplate microblogRedisTemplate;//對(duì)應(yīng)的master 為a的

關(guān)于springboot中怎么配置創(chuàng)建多個(gè)redis就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI