这篇文章主要介绍了apollo怎么更改配置刷新@ConfigurationProperties配置类的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇apollo怎么更改配置刷新@ConfigurationProperties配置类文章都会有所收获,下面我们一起来看看吧。
前言
apollo配置经常使用的方式是@value,比较便捷,如果只出现在一个类中还行,但是如果多个类中并不是很方便,特别是如果出现配置值变化了之后需要触发相关变动也无法实现,因此就会考虑使用配置类@ConfigurationProperties,它能实现:
统一管理一组配置。
配置变化的时需要触发相关变动只涉及一个bean。
但是apollo配置变化时不会把@ConfigurationProperties的值进行更新,具体看官方文档,需要配合EnvironmentChangeEvent或RefreshScope使用。
可以大概看看:
package com.ctrip.framework.apollo.use.cases.spring.cloud.zuul;import com.ctrip.framework.apollo.model.ConfigChangeEvent;import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.BeansException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.context.environment.EnvironmentChangeEvent;import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;import org.springframework.cloud.netflix.zuul.filters.RouteLocator;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;@Componentpublic class ZuulPropertiesRefresher implements ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(ZuulPropertiesRefresher.class); private ApplicationContext applicationContext; @Autowired private RouteLocator routeLocator; @ApolloConfigChangeListener(interestedKeyPrefixes = "zuul.") public void onChange(ConfigChangeEvent changeEvent) { refreshZuulProperties(changeEvent); } private void refreshZuulProperties(ConfigChangeEvent changeEvent) { logger.info("Refreshing zuul properties!"); this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys())); this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator)); logger.info("Zuul properties refreshed!"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
使用@ApolloConfigChangeListener注册了apollo配置变化监听器,内部使用了cloud发布EnvironmentChangeEvent事件进行更新。
package com.apolloconfig.apollo.demo.springboot.refresh;import com.apolloconfig.apollo.demo.springboot.config.SampleRedisConfig;import com.ctrip.framework.apollo.core.ConfigConsts;import com.ctrip.framework.apollo.model.ConfigChangeEvent;import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.cloud.context.scope.refresh.RefreshScope;import org.springframework.stereotype.Component;@ConditionalOnProperty("redis.cache.enabled")@Componentpublic class SpringBootApolloRefreshConfig { private static final Logger logger = LoggerFactory.getLogger(SpringBootApolloRefreshConfig.class); private final SampleRedisConfig sampleRedisConfig; private final RefreshScope refreshScope; public SpringBootApolloRefreshConfig( final SampleRedisConfig sampleRedisConfig, final RefreshScope refreshScope) { this.sampleRedisConfig = sampleRedisConfig; this.refreshScope = refreshScope; } @ApolloConfigChangeListener(value = "${listeners}", interestedKeyPrefixes = {"redis.cache."}) public void onChange(ConfigChangeEvent changeEvent) { logger.info("before refresh {}", sampleRedisConfig.toString()); refreshScope.refresh("sampleRedisConfig"); logger.info("after refresh {}", sampleRedisConfig); }}
package com.apolloconfig.apollo.demo.springboot.config;import com.google.common.collect.Lists;import com.google.common.collect.Maps;import java.util.List;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.InitializingBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.cloud.context.config.annotation.RefreshScope;import org.springframework.stereotype.Component;@ConditionalOnProperty("redis.cache.enabled")@ConfigurationProperties(prefix = "redis.cache")@Component("sampleRedisConfig")@RefreshScopepublic class SampleRedisConfig implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(SampleRedisConfig.class); private int expireSeconds; private String clusterNodes; private int commandTimeout; private Map<String, String> someMap = Maps.newLinkedHashMap(); private List<String> someList = Lists.newLinkedList(); @Override public void afterPropertiesSet() throws Exception { logger.info( "SampleRedisConfig initialized - expireSeconds: {}, clusterNodes: {}, commandTimeout: {}, someMap: {}, someList: {}", expireSeconds, clusterNodes, commandTimeout, someMap, someList); } public void setExpireSeconds(int expireSeconds) { this.expireSeconds = expireSeconds; } public void setClusterNodes(String clusterNodes) { this.clusterNodes = clusterNodes; } public void setCommandTimeout(int commandTimeout) { this.commandTimeout = commandTimeout; } public Map<String, String> getSomeMap() { return someMap; } public List<String> getSomeList() { return someList; } @Override public String toString() { return String.format( "[SampleRedisConfig] expireSeconds: %d, clusterNodes: %s, commandTimeout: %d, someMap: %s, someList: %s", expireSeconds, clusterNodes, commandTimeout, someMap, someList); }}
使用了RefreshScope进行刷新配置(重新create bean),但是不够高效,最理想的事一个值发生变化只要重新把对应的属性set即可。
那么我们下面尝试下,需要解决问题:
确定@ApolloConfigChangeListener.value能不能填
*
表示匹配所有namespace。根据ConfigChangeEvent找到配置类及对应的成员进行set。
解决@ApolloConfigChangeListener监听所有namespace
@ApolloConfigChangeListener(value = "*")public void onChange(ConfigChangeEvent changeEvent) { log.info("onChange changeEvent:{}", changeEvent);}
发现并不行。应该可以编程式添加listener
编程式添加listener
找到官方文档:
Config config = ConfigService.getAppConfig();config.addChangeListener(new ConfigChangeListener() { @Override public void onChange(ConfigChangeEvent changeEvent) { for (String key : changeEvent.changedKeys()) { ConfigChange change = changeEvent.getChange(key); System.out.println(String.format( "Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType())); } }});
ConfigService.getAppConfig()
默认监听application
namespace,我们需要只监听项目依赖的的namespace。
获取项目依赖的的namespace
google了一下发现:apollo配置中心之--spring boot如何加载apollo。 可以通过environment获取key为ApolloPropertySources
,我们尝试下:
@PostConstructpublic void registerApolloConfigChangeListener() { //从env中拿到所有已从Apollo加载的propertySource,获取监听的nameSpace CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources"); if (Objects.isNull(apolloPropertySources)) { return; } Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources(); //注册监听所有加载的nameSpace propertySourceList.forEach(propertySource -> { ConfigChangeListener configChangeListener = changeEvent -> { for (String changedKey : changeEvent.changedKeys()) { ConfigChange change = changeEvent.getChange(changedKey); System.out.println(String.format( "Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType())); } }; Config config = ConfigService.getConfig(propertySource.getName()); config.addChangeListener(configChangeListener); });}
寻找根据ConfigChangeEvent找到配置类及对应的成员进行set的方式
google了一下,没找到,但是spring肯定有相关的实现,比如读取yml后对 @ConfigurationProperties
属性进行填充,通过这篇文章找到ConfigurationPropertiesBindingPostProcessor是核心处理类:
通过ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization进行赋值,下面我们来看看能不能直接使用它:
package com.onepiece.apollo;import com.ctrip.framework.apollo.Config;import com.ctrip.framework.apollo.ConfigChangeListener;import com.ctrip.framework.apollo.ConfigService;import com.google.common.collect.Maps;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;import org.springframework.context.ApplicationContext;import org.springframework.core.Ordered;import org.springframework.core.env.CompositePropertySource;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.PropertySource;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import javax.annotation.Resource;import java.util.Collection;import java.util.Comparator;import java.util.Map;import java.util.Objects;import java.util.Optional;@Slf4j@Componentpublic class ApolloRefreshConfig implements BeanPostProcessor, Ordered { @Resource private ConfigurableEnvironment configurableEnvironment; private Map<String, String> configPrefixBeanNameMapping; @Resource private ConfigurationPropertiesBindingPostProcessor configurationPropertiesBindingPostProcessor; @Resource private ApplicationContext applicationContext; @PostConstruct public void registerApolloConfigChangeListener() { //从env中拿到所有已从Apollo加载的propertySource,获取监听的nameSpace CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources"); if (Objects.isNull(apolloPropertySources)) { return; } Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources(); //注册监听所有加载的nameSpace propertySourceList.forEach(propertySource -> { ConfigChangeListener configChangeListener = changeEvent -> { for (String changedKey : changeEvent.changedKeys()) { log.info("apollo changed namespace:{} Key:{} value:{}", changeEvent.getNamespace(), changedKey, changeEvent.getChange(changedKey)); String beanName = getBeanName(changedKey); configurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(applicationContext.getBean(beanName), beanName); } }; Config config = ConfigService.getConfig(propertySource.getName()); config.addChangeListener(configChangeListener); }); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { ConfigurationProperties propertiesAnno = bean.getClass().getAnnotation(ConfigurationProperties.class); if (propertiesAnno != null) { if (configPrefixBeanNameMapping == null) { configPrefixBeanNameMapping = Maps.newHashMap(); } String prefix = propertiesAnno.prefix() != null ? propertiesAnno.prefix() : propertiesAnno.value() == null ? null : propertiesAnno.value(); if (StringUtils.isNotBlank(prefix) && StringUtils.isNotBlank(beanName)) { this.configPrefixBeanNameMapping.put(prefix, beanName); } } return bean; } @Override public int getOrder() { return 0; } private String getBeanName(String key) { if (configPrefixBeanNameMapping != null) { Optional<Map.Entry<String, String>> bestMatchEntry = configPrefixBeanNameMapping.entrySet().stream() .filter(entryt -> key.startsWith(entryt.getKey() + ".")) .max(Comparator.comparing(Map.Entry<String, String>::getKey)); return bestMatchEntry.map(Map.Entry::getValue).orElse(null); } return null; }}
关于“apollo怎么更改配置刷新@ConfigurationProperties配置类”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“apollo怎么更改配置刷新@ConfigurationProperties配置类”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。