关于spring:BeanDefinition的加载过程

5次阅读

共计 23679 个字符,预计需要花费 60 分钟才能阅读完成。

BeanDefiniton 的介绍

Spring 容器的启动过程大抵能够分为两步:

  1. BeanDefinition 的加载。
  2. 容器的初始化。

咱们晓得应用 Spring 之前咱们须要先定义 Bean, 个别有两种形式定义,别离是 xml 和注解,两种形式的大同小异,都须要先将 Bean 的定义转化为 BeanDefinition, BeanDefinition 蕴含了初始化该 Bean 所须要的信息,能够认为 BeanDefinition 是 Bean 的一种形容,一种定义。BeanDefinition 是 Spring 中重要的一个构造,后续的容器中实例的初始化依赖于 BeanDefinition。

具体的加载过程

本文以 xml 为例来阐明 BeanDefinition 的加载过程。
咱们首先来看 BeanDefinition 的继承体系。

以上是 BeanDefinition 的继承体系,其中 AbstractBeanDefinitin, GenericBeanDefiniton, RootBeanDefinition, ChildBeanDefiniton 是 BeanDefiniton 加载过程中会用到的,而且其中 AbstractBeanDefinitin 是 GenericBeanDefiniton, RootBeanDefinition, ChildBeanDefiniton 的公共父类。
上面从上到下来看一下这些接口和类。

  • AttributeAccessor: 该接口申明了获取或者设置任意对象的元数据(metadata)的办法。
  • AttributeAccessorSupport: 该抽象类实现了 AttributeAccessor,定义了一个 HashMap 的属性 attributes 用于存储元数据。
  • BeanMetadataElement: 该接口只申明了一个默认办法 getSource, 用于获取配置源,配置源指的是元数据对应的源文件。
  • BeanMetadataAttributeAccessor:该类继承了 AttributeAccessorSupport 同时实现了 BeanMetadataElement,应用一个名为 source 的变量保留配置源,实现了 getSource,同时定义 setSource 用于设置配置源。
  • BeanDefinition:该接口同时继承了 BeanMetadataElement 和 AttributeAccessor 接口,定义了与 BeanDefinition 相干的常量和操作。这里对定义的常量进行简要的介绍:

    /**
     * 示意 Bean 的作用域为单例,容器中只会存在一个实例
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    
    /**
     * 示意 Bean 的作用域为原型,容器中存在多个实例
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
    
    /**
     * ROLE_APPLICATION 通常示意用户自定义的 Bean
     */
    int ROLE_APPLICATION = 0;
    
    /**
     * ROLE_SUPPORT 示意这个 Bean 是某些简单配置的撑持局部
     */
    int ROLE_SUPPORT = 1;
    
    /**
     * ROLE_INFRASTRUCTURE 示意这个 Bean 是 Spring 基础设施的一部分
     */
    int ROLE_INFRASTRUCTURE = 2;

    BeanDefinition 中定义的操作包含对 parentName,beanClassName,scope, lazyInit, dependsOn, autowireCandite, primary, factoryBeanName, factoryMethodName, propertyValues, initMethodName, destroyMethodName, role, description, resourceDescription 等属性的设置与获取。

  • AbstractBeanDefinition: 该抽象类实现了 BeanDefinition 同时继承了 BeanMetadataAttributeAccessor,该抽象类定义了 BeanDefinition 的根底属性,如下所示:

    /**
     *  默认的作用的域的名字
     */
    public static final String SCOPE_DEFAULT = "";
    /**
     * Autowire 的几种模式
     */
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    
    /**
     * 示意主动抉择一种适合的 Autowire 模式
     */
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
    
    /**
     * 示意不须要对依赖进行查看
     */
    public static final int DEPENDENCY_CHECK_NONE = 0;
    
    /**
     * 示意对援用进行依赖查看
     */
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    
    /**
     * 示意对简略属性进行依赖查看
     */
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    
    /**
     * 示意对所有的属性进行查看,包含对象的援用
     */
    public static final int DEPENDENCY_CHECK_ALL = 3;
    
    public static final String INFER_METHOD = "(inferred)";
    
    
    @Nullable
    private volatile Object beanClass;
    
    @Nullable
    private String scope = SCOPE_DEFAULT;
    
    private boolean abstractFlag = false;
    
    @Nullable
    private Boolean lazyInit;
    
    private int autowireMode = AUTOWIRE_NO;
    
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    
    @Nullable
    private String[] dependsOn;
    
    private boolean autowireCandidate = true;
    
    private boolean primary = false;
    
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
    
    @Nullable
    private Supplier<?> instanceSupplier;
    /**
     * 是否容许拜访非公有的办法
    private boolean nonPublicAccessAllowed = true;
    
    private boolean lenientConstructorResolution = true;
    
    @Nullable
    private String factoryBeanName;
    
    @Nullable
    private String factoryMethodName;
    
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    
    @Nullable
    private MutablePropertyValues propertyValues;
    
    private MethodOverrides methodOverrides = new MethodOverrides();
    
    @Nullable
    private String initMethodName;
    
    @Nullable
    private String destroyMethodName;
    
    private boolean enforceInitMethod = true;
    
    private boolean enforceDestroyMethod = true;
    /**
     * 示意该 Bean 是不是合成的,即不是利用定义的,比方 Spring 的基础设施的 Bean,或者主动代理失去的 Bean。*/
    private boolean synthetic = false;
    
    private int role = BeanDefinition.ROLE_APPLICATION;
    @Nullable
    private String description;
    @Nullable
    private Resource resource;
  • RootBeanDefinition: 该类继承了 AbstractBeanDefinition,在 AbstractBeanDefinition 的根底上减少一些属性和办法。该类能够既能够用于示意有继承关系的 BeanDefinition,也能够用于无继承关系的 BeanDefiniton。
  • GenericBeanDefinition: 该类在 AbstractBeanDefinition 的根底上新增了 parentName 的属性。GenericBeanDefinition 是规范 bean 定义的一站式服务。与任何 bean 定义一样,它容许指定类以及可选的构造函数参数值和属性值。此外,能够通过“parentName”属性灵便地配置从父 bean 定义派生。
  • ChildBeanDefinition:该类同样是在 AbstractBeanDefinition 的根底上新增了 parentName 的属性。

以上就是整个继承体系波及到的接口和类,能够看到 BeanDefinition 中蕴含的各种属性,也意味着咱们能够通过 xml 或者注解的形式指定相应的属性。

咱们能够通过 Spring 中的测试用例来看一下应用办法:

@Test
public void beanDefinitionEquality() {RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
     bd.setAbstract(true);
     bd.setLazyInit(true);
     bd.setScope("request");
     RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class);
     boolean condition1 = !bd.equals(otherBd);
     assertThat(condition1).isTrue();
     boolean condition = !otherBd.equals(bd);
     assertThat(condition).isTrue();
     otherBd.setAbstract(true);
     otherBd.setLazyInit(true);
     otherBd.setScope("request");
     assertThat(bd.equals(otherBd)).isTrue();
     assertThat(otherBd.equals(bd)).isTrue();
     assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();}

一旦咱们有了 BeanDefinition, 咱们就能够通过 BeanDefinition 初始化相应的 Bean。

接下来咱们以 xml 文件配置的形式来看一下具体的 BeanDefiniton 的加载过程。整个加载过程能够简略的分为两步:

  1. 加载 xml 文档,通过相应的 Reader 进行加载。
  2. 解析 xml 文档,通过相应的解析器进行解析,解析成 BeanDeinition。

应用实例:

SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("test.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);

其中 Registry, 用于保留 BeanDefinition, 而后通过 Resource 指定了资源文件,最初通过 XmlBeanDefinitonReader 读取并解析 xml 文件为 BeanDefinition。

能够看到下面的代码中最重要的就是 loadBeanDefinitions 的办法。在看具体的实现细节之前咱们同样先来看一下 XmlBeanDefinitonReader 相应的继承体系。

其中 BeanDefinitionReader 定义了加载 BeanDefinition 的不同形式对应的办法。AbstractBeanDefinitionReader 中定义了 registry 用于保留 BeanDefiniton, resourceLoader 用于资源的加载,beanClassLoader 用于 Class 的记录,beanNameGenerator 用于 Bean 名字的生成,同时实现了 BeanDefinitionReader 中的办法。XmlBeanDefinitonReader 中定义了更多的属性,如下:

/**
 * 默认的校验模式
 */
private int validationMode = VALIDATION_AUTO;

private boolean namespaceAware = false;
/**
 *  xml 的文件读取器对应的 Class,默认为 DefaultBeanDefinitionDocumentReader.class
 */
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
          DefaultBeanDefinitionDocumentReader.class;
/**
 * 用于报告解析过程中的问题,默认为 FailFastProblemReporter
 */
private ProblemReporter problemReporter = new FailFastProblemReporter();
/**
 * 事件监听器,默认为 EmptyReaderEventListener
 */
private ReaderEventListener eventListener = new EmptyReaderEventListener();
/**
 * 用于提取 Source,默认为 NullSourceExtractor
 */ 
private SourceExtractor sourceExtractor = new NullSourceExtractor();
/**
 * 命名空间解析器
 */ 
@Nullable
private NamespaceHandlerResolver namespaceHandlerResolver;
/**
 * 文档加载器,默认为 DefaultDocumentLoader
 */
private DocumentLoader documentLoader = new DefaultDocumentLoader();
/**
 * 实体解析器
 */
@Nullable
private EntityResolver entityResolver;
/**
 * Sax 谬误处理器,默认为 SimpleSaxErrorHandler
 */
private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);
/**
 * Xml 文档校验模式检测器
 */
private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector();

/**
 * 以后线程正在被加载的资源
 */
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
            new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"){
                @Override
                protected Set<EncodedResource> initialValue() {return new HashSet<>(4);
                }
            };

resourcesCurrentlyBeingLoaded 应用 ThreadLocal 用于保留以后线程正在加载的 Reousrce, 看完了 XmlBeanDefinitonReader 的属性,咱们对 XmlBeanDefinitonReader 的性能有了大抵的意识,接下来看具体的实现细节。

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");
     if (logger.isTraceEnabled()) {logger.trace("Loading XML bean definitions from" + encodedResource);
     }

     Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
   // 增加以后正在解析的资源
     if (!currentResources.add(encodedResource)) {
          throw new BeanDefinitionStoreException("Detected cyclic loading of" + encodedResource + "- check your import definitions!");
     }

     try (InputStream inputStream = encodedResource.getResource().getInputStream()) {InputSource inputSource = new InputSource(inputStream);
          if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());
          }
          return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
     }
     catch (IOException ex) {
          throw new BeanDefinitionStoreException("IOException parsing XML document from" + encodedResource.getResource(), ex);
     }
     finally {currentResources.remove(encodedResource);
          if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();
          }
     }
}

上述的办法先对 Resource 做了非空的一个判断,而后将 Resource 增加到 resourcesCurrentlyBeingLoaded 中去,示意正在加载,而后调用 doLoadBeanDefinitions 办法,最初清理将 Resource 从 resourcesCurrentlyBeingLoaded 移除,示意加载实现。
其中 doLoadBeanDefinitions 的定义如下:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
               throws BeanDefinitionStoreException {

     try {
          // 加载资源文件
          Document doc = doLoadDocument(inputSource, resource);
          int count = registerBeanDefinitions(doc, resource);
          if (logger.isDebugEnabled()) {logger.debug("Loaded" + count + "bean definitions from" + resource);
          }
          return count;
     }
     catch (BeanDefinitionStoreException ex) {throw ex;}
     catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line" + ex.getLineNumber() + "in XML document from" + resource + "is invalid", ex);
     }
     catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from" + resource + "is invalid", ex);
     }
     catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from" + resource, ex);
     }
     catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from" + resource, ex);
     }
     catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from" + resource, ex);
     }
}

doLoadDocument() 办法通过 JAXP(JAXP 是 Java SE 中的用来解析和操作 XML 的利用程序接口,解析 XML 文档的办法有很多,用得最多的是 DOM 和 SAX。) 对 xml 文件读取解析成 Document 对象,Document 对象蕴含了 xml 文件中的各个元素,这里不对 JAXP 进行开展,只须要晓得 Document 对象蕴含了 xml 文件中的各个元素即可。registerBeanDefinitions() 办法会对 Document 对象再次解析成 BeanDefintion 并将 BeanDefinition 注册到 Registry 中,返回本次解析的 BeanDefinition 的数量。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
     // 创立 BeanDefinitionDocumentReader,用于解析 BeanDefinition
     BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
     int countBefore = getRegistry().getBeanDefinitionCount();
     documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
     return getRegistry().getBeanDefinitionCount() - countBefore;
}

registerBeanDefinitions 先创立了 BeanDefinitionDocumentReader,而后通过 BeanDefinitionDocumentReader 去真正的解析和注册 BeanDefiniton,这里传入了 Document 和 ReaderContext, 通过 resource, problemReporter,eventListener,sourceExtractor,getNamespaceHandlerResolver 去初始化 XmlReaderContext。

/**
 * Create the {@link XmlReaderContext} to pass over to the document reader.
 */
public XmlReaderContext createReaderContext(Resource resource) {
     return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
               this.sourceExtractor, this, getNamespaceHandlerResolver());
}

接下来通过 DefaultBeanDefinitionDocumentReader 去解析和注册了。

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
     // Any nested <beans> elements will cause recursion in this method. In
     // order to propagate and preserve <beans> default-* attributes correctly,
     // keep track of the current (parent) delegate, which may be null. Create
     // the new (child) delegate with a reference to the parent for fallback purposes,
     // then ultimately reset this.delegate back to its original (parent) reference.
     // this behavior emulates a stack of delegates without actually necessitating one.
     BeanDefinitionParserDelegate parent = this.delegate;
     // delegate 初始化根结点的属性值,作为子元素的默认值
     this.delegate = createDelegate(getReaderContext(), root, parent);
     // 判断根结点是否有 namespace 的属性
     if (this.delegate.isDefaultNamespace(root)) {
          // 查问是否有 profile 的属性,如果以后的 profile 与以后的环境不匹配,则跳过
          String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
          if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
               // We cannot use Profiles.of(...) since profile expressions are not supported
               // in XML config. See SPR-12458 for details.
               if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isDebugEnabled()) {
                         logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                   "] not matching:" + getReaderContext().getResource());
                    }
                    return;
               }
          }
     }
     // 前置解决
     preProcessXml(root);
     // 解析 BeanDefinitions
     parseBeanDefinitions(root, this.delegate);
     // 后置解决
     postProcessXml(root);

     this.delegate = parent;
}

先保留旧的 BeanDefinitionParserDelegate,在解析完实现之后再换回去,因为可能含有嵌套的 beans 元素。
下面的代码中第一步通过 createDelegate 创立了 BeanDefinitionParserDelegate 对象,BeanDefinitionParserDelegate 对象中有一个 DocumentDefaultsDefinition 类型的 defaults 属性用于保留 Bean 的默认设置,这些默认的配置包含:

@Nullable
private String lazyInit;

@Nullable
private String merge;

@Nullable
private String autowire;

@Nullable
private String autowireCandidates;

@Nullable
private String initMethod;

@Nullable
private String destroyMethod;

@Nullable

持续看 createDelegate 的实现,能够看到如果上述的设置是默认值,先判断有没有 parentDefaults,如果有就应用 parentDefaults 的值,否则应用默认的,如果不是默认值,则应用指定的值。这里初始化的默认值会在后续解析子元素的时候会用到。

protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
     delegate.initDefaults(root, parentDelegate);
     return delegate;
}

public void initDefaults(Element root, @Nullable BeanDefinitionParserDelegate parent) {populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
    this.readerContext.fireDefaultsRegistered(this.defaults);
}
protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable DocumentDefaultsDefinition parentDefaults, Element root) {String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
     if (isDefaultValue(lazyInit)) {
          // Potentially inherited from outer <beans> sections, otherwise falling back to false.
          lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
     }
     defaults.setLazyInit(lazyInit);

     String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
     if (isDefaultValue(merge)) {
          // Potentially inherited from outer <beans> sections, otherwise falling back to false.
          merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
     }
     defaults.setMerge(merge);

     String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
     if (isDefaultValue(autowire)) {
          // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
          autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
     }
     defaults.setAutowire(autowire);

     if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
     }
     else if (parentDefaults != null) {defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
     }

     if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
     }
     else if (parentDefaults != null) {defaults.setInitMethod(parentDefaults.getInitMethod());
     }

     if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
     }
     else if (parentDefaults != null) {defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
     }

     defaults.setSource(this.readerContext.extractSource(root));
}

回到后面的代码,初始化 BeanDefinitionParserDelegate 之后就先判断根结点是不是默认的命名空间,即 namespace 是否为空,是否为“http://www.springframework.or…”,如果是默认的 namespace url, 则持续判断是否有 profile 属性,如果有的话,会判断以后的 environment 是否于 profile 相匹配,不匹配则间接返回。
接下来是对 Document 的前置解决 preProcessXml(), 解析 parseBeanDefinitions(), 以及后置解决 postProcessXml()。对于 DefaultBeanDefinitionDocumentReader 而言,其 preProcessXml() 和 postProcessXml() 的实现为空,持续看 parseBeanDefinitions()。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();
          for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
               if (node instanceof Element) {Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                         // 如果是默认的命名空间,即没有指定 namespace 或者位默认值 http://www.springframework.org/schema/beans
                         parseDefaultElement(ele, delegate);
                    }
                    else {
                         // 否则对自定义元素进行解析
                         delegate.parseCustomElement(ele);
                    }
               }
          }
     }
     else {delegate.parseCustomElement(root);
     }
}

能够看到在解析 root 下的各个 element 的试试,依旧会判断是否是默认的 namespace, 如果是则应用 delegate 进行解析,否则应用 namespace 对应的 handler 进行解析,自定义的 namespace 和 handler 之间的映射能够在 spring.handlers 中指定。假如是默认的 namespace,持续往下看。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
     // 如果是 import 元素
     if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);
     }
     // 如果是 alias 元素
     else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);
     }
     // 如果是 bean 元素
     else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);
     }
     // 如果是嵌套的 beans 元素
     else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
          // recurse
          doRegisterBeanDefinitions(ele);
     }
}

下面的代码对 element 的类型进行判断,不同的类型对应不同的解析形式,也能够看到如果以后解析的元素是 beans,即是一个嵌套的 beans, 则递归调用 doRegisterBeanDefinitions,这也是为什么后面要保留旧的 BeanDefinitionParserDelegate,而后创立新的,应用完之后在替换回去的起因,因为存在嵌套的 beans 元素。
同样咱们也以 bean 元素的解析为例持续往下看。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     // 解析 bean 元素
     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
     if (bdHolder != null) {
          // 依据是否有自定义的 namspace 判断是否须要对已有的元素或者属性进行装璜
          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
          try {
               // Register the final decorated instance.
               // 注册 BeanDefinition, 即保留注册 BeanDefinition 到 beanDefinitionMap, 保留 beanName 到 beanDefinitionName,以及 alias 到 aliasMap 中
               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
          }
          catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name'" +
                         bdHolder.getBeanName() + "'", ele, ex);
          }
          // Send registration event.
          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
     }
}

这里应用了 delegate.parseBeanDefinitionElement() 对元素进行解析,解析实现之后失去一个根本的 BeanDefinition 保留到 BeanDefinitionHolder 中去,之后会依据 bean 元素的对应的属性是否有 namespace 来抉择是否对 BeanDefinition 进行装璜,即对 bean 元素的属性应用 namespace 对应的 handler 进行解决。最初就是注册 BeanDefinition 了。
接下来别离看一下 parseBeanDefinitionElement 的实现和 registerBeanDefinition 的实现。

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {String id = ele.getAttribute(ID_ATTRIBUTE);
     String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

     List<String> aliases = new ArrayList<>();
     if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
          aliases.addAll(Arrays.asList(nameArr));
     }

     String beanName = id;
     if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
          // 如果没有 id,则应用 alias 的第一个元素作为 beanName
          beanName = aliases.remove(0);
          if (logger.isTraceEnabled()) {
               logger.trace("No XML'id'specified - using'" + beanName +
                         "'as bean name and" + aliases + "as aliases");
          }
     }

     if (containingBean == null) {
          // 查看 beanName 和 alias 的唯一性
          checkNameUniqueness(beanName, aliases, ele);
     }

     AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
     if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {
               // 如果没有定义 id 和 name,则生成一个
               try {if (containingBean != null) {
                         beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {beanName = this.readerContext.generateBeanName(beanDefinition);
                         // Register an alias for the plain bean class name, if still possible,
                         // if the generator returned the class name plus a suffix.
                         // This is expected for Spring 1.2/2.0 backwards compatibility.
                         String beanClassName = beanDefinition.getBeanClassName();
                         if (beanClassName != null &&
                                   beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                   !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {aliases.add(beanClassName);
                         }
                    }
                    if (logger.isTraceEnabled()) {
                         logger.trace("Neither XML'id'nor'name'specified -" +
                                   "using generated bean name [" + beanName + "]");
                    }
               }
               catch (Exception ex) {error(ex.getMessage(), ele);
                    return null;
               }
          }
          String[] aliasesArray = StringUtils.toStringArray(aliases);
          return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
     }

     return null;
}

解析的过程就是依据 xml 的定义将相应的属性解析为 BeanDefintion 的属性,首先解析了 id 和 name, 如果没有 id,则应用第一个 name 作为 beanName, 并校验 beanName 的唯一性。持续通过 parseBeanDefinitionElement() 进行解析。

@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));

     String className = null;
     if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}
     String parent = null;
     if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);
     }

     try {// 创立一个 GenericBeanDefinition,设置 beanName, parent(如果 parent 元素不为空), beanClass( 如果 readerContex 的 classLoader 不为空)
          AbstractBeanDefinition bd = createBeanDefinition(className, parent);
          // 解析 BeanDefinition 的属性,包含 scope, factory-bean, factory-method, init-method, destroy-method, lazy-init 等
          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
          // 解析 meta 子元素
          parseMetaElements(ele, bd);
          // 解析 lookup-method 子元素
          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
          // 解析 lookup-replace 子元素
          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
          // 解析 constructor-arg 子元素
          parseConstructorArgElements(ele, bd);
          // 解析 property 子元素
          parsePropertyElements(ele, bd);
          // 解析 qualifier 子元素
          parseQualifierElements(ele, bd);

          bd.setResource(this.readerContext.getResource());
          bd.setSource(extractSource(ele));

          return bd;
     }
     catch (ClassNotFoundException ex) {error("Bean class [" + className + "] not found", ele, ex);
     }
     catch (NoClassDefFoundError err) {error("Class that bean class [" + className + "] depends on not found", ele, err);
     }
     catch (Throwable ex) {error("Unexpected failure during bean definition parsing", ele, ex);
     }
     finally {this.parseState.pop();
     }

     return null;
}

上述的办法就是具体的属性的解析了,具体的解析步骤如下:

  1. 先创立了一个 GenericBeanDefinition,设置了 beanName, parentName 和 beanClassName, 如果有 classLoader 的话,生成 beanClass。而后
  2. 解析 BeanDefinition 的属性,包含 scope, factory-bean, factory-method, init-method, destroy-method, lazy-init,descrition 等。
  3. 解析 meta 子元素。
  4. 解析 lookup-method 子元素。
  5. 解析 lookup-replace 子元素。
  6. 解析 constructor-arg 子元素。
  7. 解析 property 子元素。
  8. 解析 qualifier 子元素。
  9. 设置 source 和 resource。

上述的解析都实现之后,应用 BeanDefinitionHolder 保留 BeanDefinition, beanName,alias。一个 bean 元素的解析到这里就实现了,而后对 BeanDefintion 进行注册,说简略点就是保留 beanName 到 BeanDefinition 的映射, 以及 beanName 和 alias 之间的映射。

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

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
          throws BeanDefinitionStoreException {Assert.hasText(beanName, "'beanName' must not be empty");
     Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     this.beanDefinitionMap.put(beanName, beanDefinition);
}

到这里 BeanDefinition 的加载就实现了。

最初总结一下整个 Xml 文件的 BeanDefinition 的加载过程。

  1. 指定 Xml 文件,封装成 Resource。
  2. 保留以后正在加载的 Resource 到 resourcesCurrentlyBeingLoaded 中。
  3. 应用 JAXP 加载 Xml 文件,失去 Xml 文件对应的 Document 对象。
  4. 依据 XmlBeanDefiniton 中的 documentReaderClass 实例化 BeanDefinitionDocumentReader 对象。
  5. 通过 BeanDefinitionDocumentReader 的 registerBeanDefinitions() 办法解析和注册 BeanDefinition。

    1. 创立 BeanDefinitionParserDelegate 对象,初始化默认的属性设置。
    2. 判断以后 Environment 与 profile 是否匹配。
    3. 前置解决
    4. 解析

      1. 依据跟节点的 namespace 决定解析的形式。
      2. 遍历根节点的子元素,对各个子元素进行解析。
      3. 依据子元素的类型抉择不同的解析形式。
      4. 将解析失去 BeanDefinition 注册到 Registry 中去
    5. 后置解决
  6. 返回本次解析的 BeanDefinition 的数量。
  7. 将 Resource 从 resourcesCurrentlyBeingLoaded 中移除。

总结

看完了 Xml 形式的 BeanDefinition 的解析过程,其实也能够猜想基于注解的 BeanDefinition 的解析过程大抵也差不多,惟一不同就是 Xml 的形式 BeanDefinitionDocumentReader 去解析 Document 对象,而基于注解的形式则须要 AnnotatedBeanDefinitionReader 去解析相应的注解。两种形式最终的目标都是失去 BeanDefinition 用于后续的容器初始化。

Tips

  1. 看 Spring 的源码时,能够先看相应继承体系以及类的属性,更有利于理解相应的性能。
  2. 联合 Spring 的测试用例进行 debug,也是学习 Spring 源码的一种形式。
正文完
 0