Nacos源码分析八、配置动态刷新(1)

x33g5p2x  于2021-12-20 转载在 其他  
字(9.4k)|赞(0)|评价(0)|浏览(431)

回顾一下前面分析的内容,NacosConfigAutoConfiguration定义了NacosContextRefresher监听器,监听ApplicationReadyEvent事件,当触发事件后会往nacos的configService中注册配置监听,Nacos在收到配置变更时会向applicationContext发布RefreshEvent事件。下面我们分析触发这个事件的后续操作。

首先我们定义一下测试代码:

@RestController
@RequestMapping("/refreshConfig")
@RefreshScope
public class RefreshController {
    @Value("${refresh.config}")
    private String config;

    @GetMapping
    public String getConfig(){
        return config;
    }
}

这里的refresh.config配置由nacos服务端配置:

bootstrap.yml配置:

spring:
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        prefix: demo
        group: DEMO_GROUP

  profiles:
    active: dev

在搞清楚整个流程之前,我们需要了解一些关于Spring-cloud的内容。 首先是@RefreshScope注解和RefreshScope类

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

   /**
    * @see Scope#proxyMode()
    * @return proxy mode
    */
   ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

这个@RefreshScope注解主要声明一个类的对象的作用域和刷新相关,既不是单例也不是原型,而且是会进行动态代理的。@Scope("refresh")表示他是跟refresh的作用域相关。

我们看一下spring的包扫描部分ClassPathBeanDefinitionScanner的doScan方法:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   // 遍历所有的包路径
   for (String basePackage : basePackages) {
      // 找到包下的Bean定义
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            // 设置默认值, 有个BeanDefinitionDefaults对象定义默认值
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            // Lazy、Primary、DependsOn、Role、Description
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            // 根据ScopedProxyMode生成代理Holder
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            // 注册
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

关注 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);这一行,根据scope的元数据生成对应的bean定义包装类holder:

static BeanDefinitionHolder applyScopedProxyMode(
      ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

   ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
   if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
      return definition;
   }
   boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
   return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

然后是ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);这行:

public static BeanDefinitionHolder createScopedProxy(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

   return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}

@RefreshScope的proxyMode属性默认是TARGET_CLASS,因此,这里proxyTargetClass是true。

然后是ScopedProxyUtils.createScopedProxy方法:

public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
      BeanDefinitionRegistry registry, boolean proxyTargetClass) {

   // 原bean的名字
   String originalBeanName = definition.getBeanName();
   //原bean定义
   BeanDefinition targetDefinition = definition.getBeanDefinition();
   //代理bean名字,加了scopedTarget.前缀
   String targetBeanName = getTargetBeanName(originalBeanName);

   // Create a scoped proxy definition for the original bean name,
   // "hiding" the target bean in an internal target definition.
   // 代理类的bean定义,类型是ScopedProxyFactoryBean
   RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
   //设置装饰的bean定义,把原bean定义放进去
   proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
   // 设置被代理的bean定义
   proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
   proxyDefinition.setSource(definition.getSource());
   proxyDefinition.setRole(targetDefinition.getRole());

   // targetBeanName属性注入
   proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
   if (proxyTargetClass) {
      targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
      // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
   }
   else {
      // proxyTargetClass属性注入
      proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
   }

   // Copy autowire settings from original bean definition.
   proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
   proxyDefinition.setPrimary(targetDefinition.isPrimary());
   if (targetDefinition instanceof AbstractBeanDefinition) {
      proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
   }

   // The target bean should be ignored in favor of the scoped proxy.
   targetDefinition.setAutowireCandidate(false);
   targetDefinition.setPrimary(false);

   // Register the target bean as separate bean in the factory.
   // 被代理的bean定义也会注册进去,但是beanName换掉了,是scopedTarget.XXX格式。
   registry.registerBeanDefinition(targetBeanName, targetDefinition);

   // Return the scoped proxy definition as primary bean definition
   // (potentially an inner bean).
   // 返回代理的bean定义,beanName用原来的,内容换了。外面也会注册。
   return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

分析一下这段代码:主要是多了一个bean定义,原bean定义的beanName换掉了,换成scopedTarget.xxx格式,而xxx的beanName对应的是代理类。对应的类型是ScopedProxyFactoryBean。

然后我们将目光转向spring-cloud-context的spring.factories文件:

# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration

我们看到EnableAutoConfiguration配置中有一个RefreshAutoConfiguration,点进去看一下:

@Bean
@ConditionalOnMissingBean(RefreshScope.class)
public static RefreshScope refreshScope() {
   return new RefreshScope();
}

定义了一个RefreshScope类的Bean,这个类是和@RefreshScope注解对应的, 实际上就是针对@RefreshScope注解的bean的处理器。我们点进去看一下:

public class RefreshScope extends GenericScope implements ApplicationContextAware,
      ApplicationListener<ContextRefreshedEvent>, Ordered {

看一下父类的定义:

public class GenericScope implements Scope, BeanFactoryPostProcessor,
      BeanDefinitionRegistryPostProcessor, DisposableBean {

主要实现两个处理器BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

首先是BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,在容器的bean定义注册完成后执行:

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
      throws BeansException {
   for (String name : registry.getBeanDefinitionNames()) {
      BeanDefinition definition = registry.getBeanDefinition(name);
      if (definition instanceof RootBeanDefinition) {
         RootBeanDefinition root = (RootBeanDefinition) definition;
         if (root.getDecoratedDefinition() != null && root.hasBeanClass()
               && root.getBeanClass() == ScopedProxyFactoryBean.class) {
             // 如果是ScopedProxyFactoryBean这个类型的
            if (getName().equals(root.getDecoratedDefinition().getBeanDefinition()
                  .getScope())) { // 此时name是refresh
                // 换掉类型
               root.setBeanClass(LockedScopedProxyFactoryBean.class);
                // 构造方法添加自身作为参数
               root.getConstructorArgumentValues().addGenericArgumentValue(this);
               // surprising that a scoped proxy bean definition is not already
               // marked as synthetic?
                // 合成 标记
               root.setSynthetic(true);
            }
         }
      }
   }
}

可以看到,代理类的类型从ScopedProxyFactoryBean换成了LockedScopedProxyFactoryBean,同时构造方法注入RefreshScope对象进去。

然后是BeanFactoryPostProcessor的postProcessBeanFactory方法:

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
      throws BeansException {
   this.beanFactory = beanFactory;
    // 注册refresh作用域
   beanFactory.registerScope(this.name, this);
   setSerializationId(beanFactory);
}

这个是beanFactory的后置处理器,当beanFactory准备完成后执行。主要是注册了一个作用域:refresh

@Override
public void registerScope(String scopeName, Scope scope) {
   Assert.notNull(scopeName, "Scope identifier must not be null");
   Assert.notNull(scope, "Scope must not be null");
   if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
      throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
   }
    // 添加到缓存里
   Scope previous = this.scopes.put(scopeName, scope);
   if (previous != null && previous != scope) {
      if (logger.isDebugEnabled()) {
         logger.debug("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
      }
   }
   else {
      if (logger.isTraceEnabled()) {
         logger.trace("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
      }
   }
}

总结一下

  1. 被@RefreshScope注解的类会创建一个代理类的bean定义(实际上是@Scope注解就会创建,@RefreshScope是继承了它)

  2. RefreshScope类用于处理@RefreshScope引入的代理类bean定义。主要做三件事:

  3. 把类型从ScopedProxyFactoryBean换成了LockedScopedProxyFactoryBean,同时注入了RefreshScope实例进去

为什么换类型呢?实际上ScopedProxyFactoryBean是由spring定义了,它只是定义了一个扩展作用域的规范,使用ScopedProxyFactoryBean来定义如何得到实例对象。而具体到每个扩展作用域的个性逻辑则由对应的子类实现,即:

@Scope --> @RefreshScope

ScopedProxyFactoryBean --> LockedScopedProxyFactoryBean

  1. beanFactory注册一个refresh的作用域

到这里我们基本了解了@RefreshScope和RefreshScope的作用,下面主要分析LockedScopedProxyFactoryBean是如何生成代理对象的。

相关文章