Spring核心类解析[1]BeanDeifnition

962 阅读6分钟

前言

在run方法【3】,也就是run方法中的:

 prepareContext

方法中,我们知道了在load方法里,流程构建了一个BeanDefinitionLoader,来解析配置。

此处来专门讲讲这个类以及相关的BeanDefinition。

源码解析

先来看看这个类的注解:

 Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a
 simple facade over {@link AnnotatedBeanDefinitionReader},
 {@link XmlBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}. See
 {@link SpringApplication} for the types of sources that are supported.

注解很简短,说明了这个类实际上是

  • AnnotatedBeanDefinitionReader
  • XmlBeanDefinitionReader
  • ClassPathBeanDefinitionScanner

的简单门面(simple facede)封装。

在构建的时候,这里会初始化所需的reader

 BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    Assert.notNull(registry, "Registry must not be null");
    Assert.notEmpty(sources, "Sources must not be empty");
    this.sources = sources;
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
    this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
    this.scanner = new ClassPathBeanDefinitionScanner(registry);
    this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
 }

在上层构建传参的时候,这里的registry其实就是context强转了,sources是启动的main方法的入参,以及启动类。

在之前的解析中,我们到这一步就停止了:

 void load() {
    for (Object source : this.sources) {
       load(source);
    }
 }

其实这里的load方法是个门面方法,对各种情况都做了考虑以及对应处理:

 private void load(Object source) {
    Assert.notNull(source, "Source must not be null");
    if (source instanceof Class<?>) {
       load((Class<?>) source);
       return;
    }
    if (source instanceof Resource) {
       load((Resource) source);
       return;
    }
    if (source instanceof Package) {
       load((Package) source);
       return;
    }
    if (source instanceof CharSequence) {
       load((CharSequence) source);
       return;
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
 }

一般来说,这里的sources的内容是启动类,我们就看看对应的这个针对class的装载方法好了:

 private void load(Class<?> source) {
    if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
       // Any GroovyLoaders added in beans{} DSL can contribute beans here
       GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
       ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
    }
    if (isEligible(source)) {
       this.annotatedReader.register(source);
    }
 }

这里我们SpringBoot启动并用不到Groovy,因此这里执行的是:

 this.annotatedReader.register(source);
 ​
 //
     public void register(Class<?>... componentClasses) {
         for (Class<?> componentClass : componentClasses) {
             registerBean(componentClass);
         }
     }
 ​
     public void registerBean(Class<?> beanClass) {
         doRegisterBean(beanClass, null, null, null, null);
     }
 ​
 ​

注解上说的很明确,BDLoader类确实就是一系列reader的门面,内部将source做了根据类型的对应处理。

doRegisterBean

接下来看看这个doRegisterBean:

 private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
       @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
       @Nullable BeanDefinitionCustomizer[] customizers) {
 ​
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
       return;
    }
 ​
    abd.setInstanceSupplier(supplier);
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
 ​
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    if (qualifiers != null) {
       for (Class<? extends Annotation> qualifier : qualifiers) {
          if (Primary.class == qualifier) {
             abd.setPrimary(true);
          }
          else if (Lazy.class == qualifier) {
             abd.setLazyInit(true);
          }
          else {
             abd.addQualifier(new AutowireCandidateQualifier(qualifier));
          }
       }
    }
    if (customizers != null) {
       for (BeanDefinitionCustomizer customizer : customizers) {
          customizer.customize(abd);
       }
    }
 ​
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
 }

1.创建BeanDefinition

此处来解析这部分代码:

  AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
 ​
     public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
         setBeanClass(beanClass);
         this.metadata = AnnotationMetadata.introspect(beanClass);
     }
 ​
     static AnnotationMetadata introspect(Class<?> type) {
         return StandardAnnotationMetadata.from(type);
     }
 ​
     static AnnotationMetadata from(Class<?> introspectedClass) {
         return new StandardAnnotationMetadata(introspectedClass, true);
     }

这里新建了一个AnnotatedGenericBeanDefinition

这里出现了Spring中一个重要的组件:BeanDefinition。来看看这个类(AnnotatedGenericBeanDefinition)的继承关系,这样子也方便我们后续查找相关代码:

www.processon.com/view/link/6…

结合注解,这里就是新建了一个BD对象,这个BD对象实际上包含了class作为标识符,以及类所包含的注解。

  • 这里有一个知识点:

    metadata指的是元数据,这里是类的相关信息。

    在类里面看,包括的是类相关信息,以及类包含的注解类的简略信息。

2.ABD属性解析与初步处理

这部分对应的代码为:

 if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
             return;
 }
 abd.setInstanceSupplier(supplier);
 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
 abd.setScope(scopeMetadata.getScopeName());
 String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
 ​
 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
 if (qualifiers != null) {
    for (Class<? extends Annotation> qualifier : qualifiers) {
       if (Primary.class == qualifier) {
          abd.setPrimary(true);
       }
       else if (Lazy.class == qualifier) {
          abd.setLazyInit(true);
       }
       else {
          abd.addQualifier(new AutowireCandidateQualifier(qualifier));
       }
    }
 }
 if (customizers != null) {
    for (BeanDefinitionCustomizer customizer : customizers) {
       customizer.customize(abd);
    }
 }

2.1 是否跳过bean注册

首先是判断是否应该跳过bean注册:

 if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    return;
 }
 ​
     public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
         return shouldSkip(metadata, null);
     }
 ​
     public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
         if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
             return false;
         }
 ​
         if (phase == null) {
             if (metadata instanceof AnnotationMetadata &&
                     ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
                 return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
             }
             return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
         }
 ​
         List<Condition> conditions = new ArrayList<>();
         for (String[] conditionClasses : getConditionClasses(metadata)) {
             for (String conditionClass : conditionClasses) {
                 Condition condition = getCondition(conditionClass, this.context.getClassLoader());
                 conditions.add(condition);
             }
         }
 ​
         AnnotationAwareOrderComparator.sort(conditions);
 ​
         for (Condition condition : conditions) {
             ConfigurationPhase requiredPhase = null;
             if (condition instanceof ConfigurationCondition) {
                 requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
             }
             if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
                 return true;
             }
         }
 ​
         return false;
     }

这里经过一系列特定规则的判断,来判断是否跳过bean注册。

  • 这里需要注意的是,如果没有被@Conditional标注的类,是不能跳过的。

2.2 解析并获取相关信息

这部分对应代码如下:

 abd.setInstanceSupplier(supplier);
 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
 abd.setScope(scopeMetadata.getScopeName());
 String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

supplier这里是null,根据名称应该是和ABD实例化bean相关的,后面有相关的再看看。

ScopeMetadata指的是bean对应的scope以及scope的代理行为的信息封装,在类的注释上描述得很详细了:

 Describes scope characteristics for a Spring-managed bean including the scope
 name and the scoped-proxy behavior.
 The default scope is "singleton", and the default is to not create
 scoped-proxies.

默认是scope=单例,行为是不创建scope代理。

接下来就是ABD设置bean的代理方式,并获取bean名称了。

2.3 处理BD

这部分对应代码如下:

 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
 if (qualifiers != null) {
    for (Class<? extends Annotation> qualifier : qualifiers) {
       if (Primary.class == qualifier) {
          abd.setPrimary(true);
       }
       else if (Lazy.class == qualifier) {
          abd.setLazyInit(true);
       }
       else {
          abd.addQualifier(new AutowireCandidateQualifier(qualifier));
       }
    }
 }
 if (customizers != null) {
    for (BeanDefinitionCustomizer customizer : customizers) {
       customizer.customize(abd);
    }
 }
 ​
 //
     static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
         AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
         if (lazy != null) {
             abd.setLazyInit(lazy.getBoolean("value"));
         }
         else if (abd.getMetadata() != metadata) {
             lazy = attributesFor(abd.getMetadata(), Lazy.class);
             if (lazy != null) {
                 abd.setLazyInit(lazy.getBoolean("value"));
             }
         }
 ​
         if (metadata.isAnnotated(Primary.class.getName())) {
             abd.setPrimary(true);
         }
         AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
         if (dependsOn != null) {
             abd.setDependsOn(dependsOn.getStringArray("value"));
         }
 ​
         AnnotationAttributes role = attributesFor(metadata, Role.class);
         if (role != null) {
             abd.setRole(role.getNumber("value").intValue());
         }
         AnnotationAttributes description = attributesFor(metadata, Description.class);
         if (description != null) {
             abd.setDescription(description.getString("value"));
         }
     }

这里就是对abd的一些注解,做了对应的处理:将对应的信息添加到ABD对象内;方法调用和内部的这些if做的事情都是相同的。

2.4 构建BD持有对象

这部分对应代码如下:

 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

bdHolder其实就是通过名字(以及别名)持有了一个bd。

第二步就是通过上面获取的scopeMetadata,来创建代理。(如果采用的是默认的单例scope,那么这里就没有代理)

到了第三步,就是注册BD了,这也是这部分代码中最重要的逻辑,因此单独提取出来。

[重要] 注册bd

这部分对应代码如下:

 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
 ​
 //BeanDefinitionReaderUtils
 public static void registerBeanDefinition(
             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
             throws BeanDefinitionStoreException {
 ​
         // Register bean definition under primary name.
         String beanName = definitionHolder.getBeanName();
         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
 ​
         // Register aliases for bean name, if any.
         String[] aliases = definitionHolder.getAliases();
         if (aliases != null) {
             for (String alias : aliases) {
                 registry.registerAlias(beanName, alias);
             }
         }
     }

在这里先看一下调用:

  • 实际上如果标注了别名,那么会把这些别名,都绑定到这个beanName上。

记得上面传进来的registry是什么吗?实际上就是在run流程中使用到的context-AnnotationConfigServletWebServerApplicationContext,因此这里按照继承关系,找到的对应代码在

DefaultListableBeanFactory里面:

 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
       throws BeanDefinitionStoreException {
 ​
 //1 - 验证部分代码
 ​
 //2 - 更新map
 ​
    if (existingDefinition != null || containsSingleton(beanName)) {
       resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
       clearByTypeCache();
    }
 }

1.验证

这里对应代码如下:

 Assert.hasText(beanName, "Bean name must not be empty");
 Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 ​
 if (beanDefinition instanceof AbstractBeanDefinition) {
    try {
       ((AbstractBeanDefinition) beanDefinition).validate();
    }
    catch (BeanDefinitionValidationException ex) {
       throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
             "Validation of bean definition failed", ex);
    }
 }

没什么好说的,就是验证,并让BD对自己的信息进行一下验证。

2.更新BDMap

对应代码如下,比较多,因此分成两块:

 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
 if (existingDefinition != null) {
 //如果已有了
 }
 else {
 //如果没有
 }
 //扫尾处理

这里的beanDefinitionMap也算是一个核心组件了

2.1 如果map中已有

这部分代码如下:

 if (existingDefinition != null) {
    if (!isAllowBeanDefinitionOverriding()) {
       throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    }
    else if (existingDefinition.getRole() < beanDefinition.getRole()) {
       // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
       if (logger.isInfoEnabled()) {
          logger.info("Overriding user-defined bean definition for bean '" + beanName +
                "' with a framework-generated bean definition: replacing [" +
                existingDefinition + "] with [" + beanDefinition + "]");
       }
    }
    else if (!beanDefinition.equals(existingDefinition)) {
       if (logger.isDebugEnabled()) {
          logger.debug("Overriding bean definition for bean '" + beanName +
                "' with a different definition: replacing [" + existingDefinition +
                "] with [" + beanDefinition + "]");
       }
    }
    else {
       if (logger.isTraceEnabled()) {
          logger.trace("Overriding bean definition for bean '" + beanName +
                "' with an equivalent definition: replacing [" + existingDefinition +
                "] with [" + beanDefinition + "]");
       }
    }
    this.beanDefinitionMap.put(beanName, beanDefinition);
 }

虽然代码较多,但看完实际上这里的逻辑不算复杂,就是对一些情况做了异常或日志的处理,最后更新了。

这里有一个小细节:

  • 如果这里的BeanFactory,不允许bd重载(allowBeanDefinitionOverriding = false),就会抛异常。

2.2 如果没有

 else {
    if (hasBeanCreationStarted()) {
       // Cannot modify startup-time collection elements anymore (for stable iteration)
       synchronized (this.beanDefinitionMap) {
          this.beanDefinitionMap.put(beanName, beanDefinition);
          List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
          updatedDefinitions.addAll(this.beanDefinitionNames);
          updatedDefinitions.add(beanName);
          this.beanDefinitionNames = updatedDefinitions;
          removeManualSingletonName(beanName);
       }
    }
    else {
       // Still in startup registration phase
       this.beanDefinitionMap.put(beanName, beanDefinition);
       this.beanDefinitionNames.add(beanName);
       removeManualSingletonName(beanName);
    }
    this.frozenBeanDefinitionNames = null;
 }

这里出现了一个关键的节点:hasBeanCreationStarted(),具体的判断逻辑是:

 !this.alreadyCreated.isEmpty();

就涉及到了又一个关键的组件。但这里只做查找并不做更新,因此留到后面对BeanFactory的解释中再做研究。

这里实际上也很简单,如果bean的创建已经开始了:

  • 那么此时为了维护迭代的稳定性,此时就把beanDefinition锁上,在方法内部做更新操作。

没有的话就一样,不锁,更新。

这里的frozenBeanDefinitionNames,一样不知道是啥东西,一样留到BeanFactory里再做深入研究。

2.3 扫尾处理

 if (existingDefinition != null || containsSingleton(beanName)) {
    resetBeanDefinition(beanName);
 }
 else if (isConfigurationFrozen()) {
    clearByTypeCache();
 }

至此为止就更新完了对应的BD,最后为了维护类内部的稳定性,做了一些特定的处理,这些我们一样留到对BeanFactory的研究中再一探究竟。

总结

到这里就把对BeanDefinitionLoader以及BeanDefinition的源码大致看了一遍。

有几个核心的关键点:

  • 对于BeanDefinitionLoader,实际上是一个多种解析方式的门面集合。
  • BeanDefinition实际上对于Spring而言,类似于Bean的身份证信息,记录了类以及类相关注解的信息。