Principle and application of spring cloud @ refreshscope

@Refreshscope

To clarify refreshscope, first understand scope

Scope and ApplicationContext lifecycle

Abstractbeanfactory#dogetbean create bean instance

 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 and prototype are hard coded and are not subclasses of scope. Scope is actually an interface for custom extensions

Scope bean instances are created by scope itself. For example, sessionscope gets instances from session, threadscope gets instances from ThreadLocal, and refreshscope gets instances from built-in cache.

@Instantiation of scope objects

@Refreshscope is the @ scope of scopename = "Refresh"

 ...
 @Scope("refresh")
 public @interface RefreshScope {
   ...
 }

@Annotatedbeandefinitionreader#registerbean registered for scope

 public void registerBean(...){
  ...
  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
  ...
   deFinitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,deFinitionHolder,this.registry);
 }

Read @ scope metadata, 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);
     }
}

The scope instance object is created through the scopedproxyfactorybean, which implements the scopedobject interface through AOP. It will not be expanded here

Now let's talk about how refreshscope implements configuration and instance refresh

RefreshAutoConfiguration#RefreshScopeConfiguration

 @Component
 @ConditionalOnMissingBean(RefreshScope.class)
 protected static class RefreshScopeConfiguration implements BeanDeFinitionRegistryPostProcessor{
 ...
   registry.registerBeanDeFinition("refreshScope",BeanDeFinitionBuilder.genericBeanDeFinition(RefreshScope.class)
             .setRole(BeanDeFinition.ROLE_INFRASTRUCTURE)
             .getBeanDeFinition());
 ...
 }

Register yourself with abstractbeanfactory in genericscope#postprocessbeanfactory

public class GenericScope implements Scope,beanfactoryPostProcessor...{
   @Override
   public void postProcessbeanfactory(ConfigurableListablebeanfactory beanfactory)
     throws BeansException {
     beanfactory.registerScope(this.name/*refresh*/,this/*RefreshScope*/);
     ...
   }
}

@H_ 369_ 18@RefreshScope Refresh process

The entry is in contextrefresh #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();
 }

① Extract all parameter variables except the standard parameters (system, JNDI, servlet), ② reload the parameters in the original environment under a new spring context container, and then close the new container ③ lift the updated parameters (excluding the standard parameters) ④ compare the change items ⑤ publish the environment change event, Receiving: environmentchangelistener / loggingrebinder ⑥ refreshscope regenerates the bean with new environment parameters. The process of regenerating is very simple. Clear the refreshscope cache and destroy the bean. Next time, a new instance will be obtained from beanfactory (the instance uses the new configuration)

 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>
   }
 }

How does spring cloud bus trigger refresh

Busautoconfiguration #busrefreshconfiguration publishes a 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 triggers the broadcast refreshremoteapplicationevent event from the HTTP port

 @Endpoint(id = "bus-refresh")
 public class RefreshBusEndpoint extends AbstractBusEndpoint {
    public void busRefresh() {
     publish(new RefreshRemoteApplicationEvent(this,getInstanceId(),null));
   }
 }

Busautoconfiguration #refreshlistener is responsible for receiving events (all nodes configured with 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 triggers contextrefresher

public void onApplicationEvent(RefreshRemoteApplicationEvent event) {
   Set<String> keys = contextRefresher.refresh();
 }

Most of the services that need to be updated need to be marked with @ refreshscope. How does Eureka client configure the update

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

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>