当前位置: 首页 > article >正文

Spring Cloud Config 动态刷新原理分析

Spring Cloud Config的数据刷新机制

底层工作原理依赖于Sping Actuator组件,在数据源发生变化的时候调用 /actuator/refresh 来应用实例完成config配置的的刷新

可以刷新的配置主要有两种形式一种是

1、@ConfigurationProperties 声明的配置类

2、@RefreshScope声明的bean

刷新流程源码分析

  1. 调用 /actuator/refresh 端点
  2. 刷新环境属性(ContextRefresher
  3. 发布 EnvironmentChangeEvent 事件
  4. 动态更新 Bean

接下来我们将结合源码来分析每个步骤。


1. 调用 /actuator/refresh 端点

当你调用 /actuator/refresh 端点时,Spring Actuator 的 RefreshEndpoint 类会处理这个请求。

RefreshEndpoint 类(暴露 /refresh 端点):
/**
 * @author Dave Syer
 * @author Venil Noronha
 */
@ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)
@ManagedResource
public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {

  private ContextRefresher contextRefresher;

  public RefreshEndpoint(ContextRefresher contextRefresher) {
    super("refresh");
    this.contextRefresher = contextRefresher;
  }

  @ManagedOperation
  public String[] refresh() {
    Set<String> keys = contextRefresher.refresh();
    return keys.toArray(new String[keys.size()]);
  }

  @Override
  public Collection<String> invoke() {
    return Arrays.asList(refresh());
  }

}

  • contextRefresher.refresh():实际的配置刷新逻辑由 ContextRefresher 完成。

/refresh 端点被调用时,RefreshEndpoint 会触发 ContextRefresher.refresh() 方法。


2. 刷新环境属性(ContextRefresher

ContextRefresher 类是配置刷新流程的核心,它负责重新加载环境中的配置并触发配置变更事件。关键方法是 refresh(),如下所示:

ContextRefresher 类:
  public synchronized Set<String> refresh() {
    Map<String, Object> before = extract(
        this.context.getEnvironment().getPropertySources());
    addConfigFilesToEnvironment();
    Set<String> keys = changes(before,
        extract(this.context.getEnvironment().getPropertySources())).keySet();
    this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
    this.scope.refreshAll();
    return keys;
  }
  • environmentManager.reload():通过 EnvironmentManager 从远程配置中心重新加载配置。它会将新的配置值注入到 Spring 的 Environment 中,并返回那些发生变化的配置键。
  • publishEvent(new EnvironmentChangeEvent(...)):如果配置有变化,ContextRefresher 会发布 EnvironmentChangeEvent 事件,将变化的配置键传递给应用上下文。
  • context.refresh():有些情况下可能会调用 ApplicationContext.refresh() 方法以刷新整个上下文(这不是必须的,具体依赖应用场景)。

ContextRefresher 是整个配置刷新的核心,它通过 EnvironmentManager 从远程配置中心重新加载配置,并在有变化时发布 EnvironmentChangeEvent 事件。


3. 发布 EnvironmentChangeEvent 事件

EnvironmentChangeEvent 是 Spring 框架中的一个事件,用来通知应用中的相关组件,某些环境属性已经发生了变化。

/**
 * Event published to signal a change in the {@link Environment}.
 * 
 * @author Dave Syer
 *
 */
@SuppressWarnings("serial")
public class EnvironmentChangeEvent extends ApplicationEvent {

  private Set<String> keys;

  public EnvironmentChangeEvent(Set<String> keys) {
    // Backwards compatible constructor with less utility (practically no use at all)
    this(keys, keys);
  }

  public EnvironmentChangeEvent(Object context, Set<String> keys) {
    super(context);
    this.keys = keys;
  }

  /**
   * @return the keys
   */
  public Set<String> getKeys() {
    return keys;
  }

}

EnvironmentChangeEvent 类:
  • ApplicationEventEnvironmentChangeEvent 继承了 Spring 的 ApplicationEvent,是一种标准的事件模型。它封装了当前的 ApplicationContext 和那些已经发生变化的配置键。
  • getKeys():提供方法来获取所有发生变化的配置键。

事件发布之后,Spring 容器中那些监听 EnvironmentChangeEvent 事件的组件会相应地做出反应。通常,使用 @ConfigurationProperties@RefreshScope 的 Bean 会监听这个事件,并更新其绑定的属性。


4. 动态更新 Bean

EnvironmentChangeEvent 被发布时ConfigurationPropertiesRebinder 接收到通知,会对Bean进行销毁并且重新完成初始化以此来达到刷新配置属性的目的

具体流程:
  @ManagedOperation
  public boolean rebind(String name) {
    if (!this.beans.getBeanNames().contains(name)) {
      return false;
    }
    if (this.applicationContext != null) {
      try {
        Object bean = this.applicationContext.getBean(name);
        if (AopUtils.isAopProxy(bean)) {
          bean = ProxyUtils.getTargetObject(bean);
        }
        this.applicationContext.getAutowireCapableBeanFactory().destroyBean(bean);
        this.applicationContext.getAutowireCapableBeanFactory()
            .initializeBean(bean, name);
        return true;
      }
      catch (RuntimeException e) {
        this.errors.put(name, e);
        throw e;
      }
    }
    return false;
  }

http://www.kler.cn/a/312498.html

相关文章:

  • 红日靶机(七)笔记
  • 华为大咖说 | 浅谈智能运维技术
  • mapreduce 将数据清洗后保存到 hbase
  • 使用Matlab神经网络工具箱
  • 设计模式-七个基本原则之一-单一职责原则 + SpringBoot案例
  • 如何优化Elasticsearch的查询性能?
  • 视频单目标跟踪研究
  • 鸿蒙next web组件和h5 交互实战来了
  • 零基础到项目实战:Node.js版Selenium WebDriver教程
  • Gitee Pipeline 从入门到实战【详细步骤】
  • Spring Boot框架下校园信息管理平台的构建
  • Unborn安装CUDA Toolkit 12.2
  • android10 系统定制:增加应用使用数据埋点,应用使用时长统计
  • 2013-2023年专精特新小巨人企业财务指标数据
  • MySQL 数据库备份与恢复指南
  • 抖音下载别人作品怎么去掉水印
  • Spring Boot 集成 Redisson 实现消息队列
  • 【C#生态园】提升C#开发效率:深入了解自然语言处理库与工具
  • (Java企业 / 公司项目)点赞业务系统设计-批量查询点赞状态(二)
  • 探索未来智能:Moonshot AI 引领AI新纪元——M1超级模型
  • css百分比布局中height:100%不起作用
  • 牛客小白月赛101(栈、差分、调和级数、滑动窗口)
  • Java中out流中打印方法详解
  • 【设计模式-享元】
  • 深度学习后门攻击分析与实现(一)
  • 基于python+django+vue的家居全屋定制系统