iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >apollo怎么更改配置刷新@ConfigurationProperties配置类
  • 170
分享到

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

2023-07-05 22:07:42 170人浏览 泡泡鱼
摘要

这篇文章主要介绍了apollo怎么更改配置刷新@ConfigurationProperties配置类的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇apollo怎么更改配置刷新@ConfigurationProp

这篇文章主要介绍了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()默认监听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配置类”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

    --结束END--

    本文标题: apollo怎么更改配置刷新@ConfigurationProperties配置类

    本文链接: https://www.lsjlt.com/news/355722.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • c#文本框只读属性怎么设置
      c# 文本框只读属性的设置 问题:如何设置 C# 文本框的只读属性? 回答: 要设置文本框的只读属性,可以使用 ReadOnly 属性。 详细解释: ReadOnly 属性是一个布尔值属...
      99+
      2024-05-14
      c#
    • 如何使用 Golang ORM 工具与数据库交互?
      使用 gorm orm 工具与数据库交互,可通过以下步骤轻松实现:安装和初始化(1)、定义模型(2)、建立映射(3)、创建记录(4)、读取记录(5)、更新记录(6)、删除记录(7)、事务...
      99+
      2024-05-14
      golang orm mysql git iphone
    • c++中double与float的区别
      c++++ 中 double 与 float 的区别 在 C++ 中,double 和 float 都是浮点数类型,但它们在精度、范围和内存占用方面存在差异。 精度: double:双...
      99+
      2024-05-14
      c++ 内存占用
    • 如何在 Golang 中处理数据库错误?
      在 go 中处理数据库错误的步骤包括:使用专门的 go mysql 驱动程序。实现 error 接口以创建自定义错误。检测错误,记录足够的信息,并基于错误类型执行适当的恢复操作。 如何...
      99+
      2024-05-14
      golang 数据库错误 mysql git 数据丢失
    • c++中int怎么转string
      在 c++ 中将 int 转换为 string 的方法有:使用 to_string() 函数直接转换。使用 stringstream 类。使用 sprintf() 函数。 如何在 C+...
      99+
      2024-05-14
      c++
    • 优化 C++ 服务器架构以提高吞吐量
      优化 c++++ 服务器吞吐量策略:线程池:预先创建线程池,快速响应请求。非阻塞 i/o:在等待 i/o 时执行其他任务,提升吞吐量。http/2:使用二进制协议,支持多路复用和内容压缩...
      99+
      2024-05-14
      优化 服务器架构 c++
    • 使用 C++ 堆分配器管理服务器架构中的内存
      使用 c++++ 堆分配器管理服务器内存可提高性能和稳定性。堆分配器负责分配和释放动态内存,跟踪空闲/已分配内存元数据。在服务器架构中,它用于分配应用程序对象、缓冲区和数据结构。选择堆分...
      99+
      2024-05-14
      c++ 内存管理 并发访问
    • c#怎么获取字符串中的数字
      从 c# 字符串中提取数字的方法有五种:正则表达式、循环和 char.isdigit()、int.tryparse()、string.split() 和 int.parse()、linq...
      99+
      2024-05-14
      git c#
    • C++ 异常处理在服务器架构中的最佳实践
      c++++ 异常处理在服务器架构的最佳实践:定义清晰的异常层次结构,使用自定义异常类型封装相关信息。使用异常安全函数,及时在适当范围内处理异常。提供有意义的错误消息,帮助用户了解错误并采...
      99+
      2024-05-14
      c++ 异常处理
    • c#怎么拼接字符串
      在 c# 中拼接字符串有三种方法:使用加法(+)运算符、string.concat() 方法和 stringbuilder 类。最简单的方法是使用 + 运算符将字符串连接起来,...
      99+
      2024-05-14
      c#
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作