@RefreshScope详解

2023-11-13

要说清楚RefreshScope,先要了解Scope

  • Scope(org.springframework.beans.factory.config.Scope)是Spring 2.0开始就有的核心的概念
  • RefreshScope(org.springframework.cloud.context.scope.refresh)是spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载。
  • Scope -> GenericScope -> RefreshScope

    @RefreshScope那些事@RefreshScope那些事@RefreshScope那些事

    scope_hierarchy.jpeg

  • Scope与ApplicationContext生命周期
    • AbstractBeanFactory#doGetBean创建Bean实例
     protected <T> T doGetBean(...){
        final RootBeanDefinition mbd = ...
        if (mbd.isSingleton()) {
            ...
        } else if (mbd.isPrototype())
           ...
        } else {
              String scopeName = mbd.getScope();
              final Scope scope = this.scopes.get(scopeName);
              Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {...});
              ...
        }
        ...
     }
    • Singleton和Prototype是硬编码的,并不是Scope子类。 Scope实际上是自定义扩展的接口
    • Scope Bean实例交由Scope自己创建,例如SessionScope是从Session中获取实例的,ThreadScope是从ThreadLocal中获取的,而RefreshScope是在内建缓存中获取的。
  • @Scope 对象的实例化
    • @RefreshScope 是scopeName=”refresh”的 @Scope
     ...
      @Scope("refresh")
      public @interface RefreshScope {
          ...
      }
    • @Scope 的注册 AnnotatedBeanDefinitionReader#registerBean
      public void registerBean(...){
        ...
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
          abd.setScope(scopeMetadata.getScopeName());
        ...
          definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
      }
    • 读取@Scope元数据, AnnotationScopeMetadataResolver#resolveScopeMetadata
    public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
              AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
                      annDef.getMetadata(), Scope.class);
              if (attributes != null) {
                  metadata.setScopeName(attributes.getString("value"));
                  ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
                  if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
                      proxyMode = this.defaultProxyMode;
                  }
                  metadata.setScopedProxyMode(proxyMode);
              }
    }
    • Scope实例对象通过ScopedProxyFactoryBean创建,其中通过AOP使其实现ScopedObject接口,这里不再展开

现在来说说RefreshScope是如何实现配置和实例刷新的

  • RefreshScope注册
    • RefreshAutoConfiguration#RefreshScopeConfiguration
      @Component
      @ConditionalOnMissingBean(RefreshScope.class)
      protected static class RefreshScopeConfiguration implements BeanDefinitionRegistryPostProcessor{
      ...
          registry.registerBeanDefinition("refreshScope",
          BeanDefinitionBuilder.genericBeanDefinition(RefreshScope.class)
                              .setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
                              .getBeanDefinition());
      ...
      }
    • RefreshScope extends GenericScope, 大部分逻辑在 GenericScope 中
    • GenericScope#postProcessBeanFactory 中向AbstractBeanFactory注册自己
    public class GenericScope implements Scope, BeanFactoryPostProcessor...{
          @Override
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
              throws BeansException {
              beanFactory.registerScope(this.name/*refresh*/, this/*RefreshScope*/);
              ...
          }
    }
  • RefreshScope 刷新过程
    • 入口在ContextRefresher#refresh
     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(keys));
          this.scope.⑥refreshAll();
     }
    • ①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量
    • ②把原来的Environment里的参数放到一个新建的Spring Context容器下重新加载,完事之后关闭新容器
    • ③提起更新过的参数(排除标准参数)
    • ④比较出变更项
    • ⑤发布环境变更事件,接收:EnvironmentChangeListener/LoggingRebinder
    • ⑥RefreshScope用新的环境参数重新生成Bean
    • 重新生成的过程很简单,清除refreshscope缓存幷销毁Bean,下次就会重新从BeanFactory获取一个新的实例(该实例使用新的配置)
    • RefreshScope#refreshAll
      public void refreshAll() {
              <b>super.destroy();</b>
              this.context.publishEvent(new RefreshScopeRefreshedEvent());
      }
    • GenericScope#destroy
      public void destroy() {
          ...
          Collection<BeanLifecycleWrapper> wrappers = <b>this.cache.clear()</b>;
          for (BeanLifecycleWrapper wrapper : wrappers) {
              <b>wrapper.destroy();</b>
          }
      }
  • Spring Cloud Bus 如何触发 Refresh
    • BusAutoConfiguration#BusRefreshConfiguration 发布一个RefreshBusEndpoint
    @Configuration
      @ConditionalOnClass({ Endpoint.class, RefreshScope.class })
      protected static class BusRefreshConfiguration {
    
          @Configuration
          @ConditionalOnBean(ContextRefresher.class)
          @ConditionalOnProperty(value = "endpoints.spring.cloud.bus.refresh.enabled", matchIfMissing = true)
          protected static class BusRefreshEndpointConfiguration {
              @Bean
              public RefreshBusEndpoint refreshBusEndpoint(ApplicationContext context,
                      BusProperties bus) {
                  return new RefreshBusEndpoint(context, bus.getId());
              }
          }
      }
    • RefreshBusEndpoint 会从http端口触发广播RefreshRemoteApplicationEvent事件
     @Endpoint(id = "bus-refresh")
      public class RefreshBusEndpoint extends AbstractBusEndpoint {
           public void busRefresh() {
              publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), null));
          }
      }
    • BusAutoConfiguration#refreshListener 负责接收事件(所有配置bus的节点)
      @Bean
      @ConditionalOnProperty(value = "spring.cloud.bus.refresh.enabled", matchIfMissing = true)
      @ConditionalOnBean(ContextRefresher.class)
      public RefreshListener refreshListener(ContextRefresher contextRefresher) {
          return new RefreshListener(contextRefresher);
      }
    • RefreshListener#onApplicationEvent 触发 ContextRefresher
    public void onApplicationEvent(RefreshRemoteApplicationEvent event) {
          Set<String> keys = contextRefresher.refresh();
      }
  • 大部分需要更新的服务需要打上@RefreshScope, EurekaClient是如何配置更新的
    • EurekaClientAutoConfiguration#RefreshableEurekaClientConfiguration
      @Configuration
      @ConditionalOnRefreshScope
      protected static class RefreshableEurekaClientConfiguration{
          @Bean
          @RefreshScope
          public EurekaClient eurekaClient(...) {
              return new CloudEurekaClient(manager, config, this.optionalArgs,
                      this.context);
          }
          
          @Bean
          @RefreshScope
          public ApplicationInfoManager eurekaApplicationInfoManager(...) {
              ...
              return new ApplicationInfoManager(config, instanceInfo);
          }
      }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

@RefreshScope详解 的相关文章

  • matlab 虚数 .,关于MATLAB在复数方面的应用 – MATLAB中文论坛

    最近 看到有不少朋友问MATLAB在复数方面的应用问题 特此发个帖子 给大家分享点资料 matlab在复数中的应用 1 复数的生成 复数生成语句 其中theta为复数辐角的弧度值 r为复数的模 z a b i z a bi z r exp
  • 小程序上传图片(拍照或从相册选择)chooseMedia

    let that this wx chooseMedia count 1 最多可以选择的图片张数 默认9 mediaType image sourceType album camera success res console log res
  • CSS flex 属性

    flex basis flex basis属性规定弹性项目的初始长度 那么我们随便写一串简单的代码来看看flex basis的效果如何 代码如下
  • DVWA low难度全通关

    low难度 1 暴力破解 抓包 破解成功 2 命令执行 我们可以用通道符绕过 也行 3 跨站请求伪造 这里把url发给登陆了的用户 就可以密码修改成功了 4 文件包含 通过这样来访问到phpinfo php 5 文件上传 毫无防备 可以直接
  • Python目前建议最好安装什么版本的?

    Python2 7及以前的版本 已经被淘汰了 图片来源 Python1 1 1 6下载地址 https www python org download releases 在Python1 5 2版本之前 Python官网只提供源代码的下载

随机推荐

  • 使用stream将List转换为用逗号拼接的字符串

    摘要 有时候需要将List中的元素转换为用逗号拼接的字符串 很简单的实现 略略写一下stream的实现 实现 使用stream实现 public void test List
  • Linux多线程:线程分离

    第三方的线程库 Compile and link with pthread The pthread detach function marks the thread identified by thread as detached When
  • python14异常处理

    1 错误 有的错误是程序编写有问题造成的 比如本来应该输出整数结果输出了字符 串 这种错误我们通常称之为 bug bug 是必须修复的 有的错误是用户输入造成的 比如让用户输入 email 地址 结果得到一个空字 符串 这种错误可以通过检查
  • 克鲁斯卡尔算法(kruskal)

    我自己感觉 克鲁斯卡尔算法比普利姆算法更好理解 它就两个要点 排序和判断是否成环 排序 我们把两两相邻的边根据边的权值 从小到大依次排序 这个十大排序算法可以自己选一个去实现下 刚好还可以回忆下以前的算法 下面我们使用冒泡来实现边的排序 是
  • CentOS8搭建Web服务器笔记1 Nginx+Php8基础环境

    CentOS8搭建Web服务器笔记1 Nginx Php8基础环境 1 Nginx 1 1 Yum工具安装 1 1 1 查询Yum默认安装源版本 1 1 2 配置最新安装源 1 1 3 yum安装nginx 1 1 4 启动nginx服务
  • 4.4 Go语言中的单元测试

    基本概念 上一节提到 代码完成的标准之一还包含了单元测试 这部分也是很多开发流程中不规范的地方 写过单元测试的开发人员应该理解 单元测试最核心的价值是为了证明 为什么我写的代码是正确的 也就是从逻辑角度帮你检查你的代码 但是另外一方面 如果
  • 谈谈古典的《拆掉思维里的墙》

    写在前面 这是考完高考 拿到深圳大学录取通知书之后 年级发布的第一个作业 就是看一篇年级推荐的书写一篇读后感 不过写完回校之后年级居然把这事给忘记了 写了文章没人看不是很好 于是就放上C站呆着 留点痕迹 也许算正文 距离上一次写读后感已经不
  • 决策树(Decision Tree)

    文章目录 1 决策树简介 2 决策树原理 2 1 引例 2 2 生成算法 2 2 1 ID3 信息增益 2 2 2 C4 5 信息增益率 2 2 3 CART 基尼指数 2 3 三种算法的对比 2 4 剪枝处理 2 4 1 预剪枝 2 4
  • 怎么让VSCode标签栏只展示一个窗口

    怎么让VSCode标签栏只展示一个窗口 问题 解决方法 参考 问题 我们希望VSCode窗口的标签栏是这么分开显示标签的 但是 偶尔重启该应用 会突然发现变成了只显示一个标签 不会再分开展示了 变成了一个文件名加路径了 这种情况下原来的标签
  • Oracle 表空间、段、区、块概述

    文章目录 图示 表空间 tablespace 数据段 segment 区 extent 数据块 block 图示 修改中 请稍等 段 存在于 表空间 中 段 是 区 的集合 区 是 数据块 的集合 数据块 会映射到 磁盘块 以实体 关系图的
  • Request_获取请求参数通用方式介绍

    1 获取请求参数通用方式 不论get还是post请求方式都可以使用下列方法来获取请求参数 1 String getParameter String name 根据参数名称获取参数值 username zs password 123 2 St
  • 除了Midjourney和Stable Diffusion,还有哪些AI模型可以使用

    Midjourney是一款广受设计师和艺术家欢迎的人工智能图像生成器 然而 最近它停止提供免费试用 让许多用户开始寻找替代品 在本文中 我们为您编制了一个2023年可尝试的十大Midjourney替代品列表 我们包括了免费和付费选项 让您可
  • [台服公主链接]修改ROOT检测

    类路径 Project smali jp co cygames androidroot CheckApp smali 原始代码 method public static isRootUser Z locals 7 prologue cons
  • CSS Flex相关属性(自我总结)

    把容器做成flex弹性盒 display flex 容器属性 1 flex direction 项目排列方向 主轴方向 row 左对齐 横向排列 默认 row reverse 右对齐 反转横向排列 column 纵向排列 column re
  • JAVA 计算日期属于当月第几周(日期周计算)

    JAVA 计算日期属于当月第几周 日期周计算 本文周计算时间方式为 当月第一个周一为第一周 计算 获取月第一个周一 从当月第一天开始找 第一个周一时间与 sourceTime 传入时间对比 sourceTime在第一个周一时间之前 表示属于
  • Twitter开发者账号及开发者APPs的创建 2019.05

    转自 https towardsdatascience com access data from twitter api using r and or python b8ac342d3efe Access Data from Twitter
  • screen / nohup 实现后台运行程序

    通常我们在运行程序时 会通过终端登录服务器 然后使用shell命令运行程序 这种方式对于运行时长较短的程序没问题 但是对于深度学习中训练网络等耗时较长的程序来说很容易出问题 例如一旦机器死机 断网 不小心关闭终端等种种情况都会导致程序终止运
  • JSP中include指令的功能简介说明

    转自 JSP中include指令起什么用呢 下文讲述JSP中include指令的功能简介说明 如下所示 JSP中include指令的功能说明 用于将不同的文件插入到当前JSP页面的指定位置 JSP指令的语法 相关说明 include指令 用
  • 现代大学英语精读第二版(第四册)学习笔记(原文及全文翻译)——1A - Thinking as a Hobby(把思考作为爱好)

    Unit 1A Thinking as a Hobby Thinking as a Hobby William Golding While I was still a boy I came to the conclusion that th
  • @RefreshScope详解

    要说清楚RefreshScope 先要了解Scope Scope org springframework beans factory config Scope 是Spring 2 0开始就有的核心的概念 RefreshScope org s