- 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());
  }
  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);
      }
  }