文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

apollo怎么更改配置刷新@ConfigurationProperties配置类

2023-07-05 22:27

关注

这篇文章主要介绍了apollo怎么更改配置刷新@ConfigurationProperties配置类的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇apollo怎么更改配置刷新@ConfigurationProperties配置类文章都会有所收获,下面我们一起来看看吧。

前言

apollo配置经常使用的方式是@value,比较便捷,如果只出现在一个类中还行,但是如果多个类中并不是很方便,特别是如果出现配置值变化了之后需要触发相关变动也无法实现,因此就会考虑使用配置类@ConfigurationProperties,它能实现:

但是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监听所有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()默认监听applicationnamespace,我们需要只监听项目依赖的的namespace。

获取项目依赖的的namespace

google了一下发现:apollo配置中心之--spring boot如何加载apollo。 可以通过environment获取key为ApolloPropertySources,我们尝试下:

apollo怎么更改配置刷新@ConfigurationProperties配置类

@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是核心处理类:

apollo怎么更改配置刷新@ConfigurationProperties配置类

通过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配置类”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯