Spring 5 源码解析- XML中Bean配置加载

        spring-framework 加载配置文件过程:

        根据业务系统运行的环境,选择 ApplicationContext 接口合适的实现类,启动系统先初始化上下文环境,然后通过BeanDefinitionReader 的实现类读取Bean的配置文件。这里配置文件可以是 xml文件,properties文件,yml文件等,也可以是注解形式扫描配置。配置文件读取成功后,将相应的配置转换成 BeanDefinition 的对象实例保存在DefaultListableBeanFactory#beanDefinitionMap 中。紧接着,根据配置的 BeanFactoryPostProcessor 对象列表,进行 BeanDefinition 的扩展处理。(  例如 org.springframework.beans.factory.config.PlaceholderConfigurerSupport:  ${} 配置转换成实际的值实现类。org.springframework.beans.factory.config.PropertyOverrideConfigurer: 将 beanName.property 替换成实际的值。 )  

                                                                               -->   xml配置

                                                                               |

ApplicationContext ---> BeanDefinitionReader -+----> yml配置 -----> BeanDefinition ---> DefaultListableBeanFactory  --->  BeanFactoryPostProcessor 

                                                                               |

                                                                               --> Annotation 扫描

    这里以 XML 配置的BeanDefinition 进行源码加载分析:

 扫VX 领Java资料,前端,测试,python等等资料都有

一. BeanFactory 实例的创建

      在 AbstractApplicationContext#obtainFreshBeanFactory 方法中,是进行 bean 处理的入口。

            AbstractApplicationContext#obtainFreshBeanFactory

                   -> AbstractRefreshableApplicationContext#refreshBeanFactory

        1.检测是否已经创建 BeanFactory 。如果创建了则销毁BeanFactory 相关的属性。

        2.创建 BeanFactory 接口的默认实现类  DefaultListableBeanFactory 实例。

        3.客户化 BeanFactory 处理。

        4.加载 BeanDefinition 定义信息。

复制代码

 1     /**
 2      * This implementation performs an actual refresh of this context's underlying
 3      * bean factory, shutting down the previous bean factory (if any) and
 4      * initializing a fresh bean factory for the next phase of the context's lifecycle.
 5      */
 6     @Override
 7     protected final void refreshBeanFactory() throws BeansException {
 8         if (hasBeanFactory()) {
 9             destroyBeans();
10             closeBeanFactory();
11         }
12         try {
13             DefaultListableBeanFactory beanFactory = createBeanFactory();
14             beanFactory.setSerializationId(getId());
15             customizeBeanFactory(beanFactory);
16             loadBeanDefinitions(beanFactory);
17             this.beanFactory = beanFactory;
18         }
19         catch (IOException ex) {
20             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
21         }
22     }

复制代码

二. ApplicationContex 读取 BeanDefinition 的加载分析

        这里我们分析 XML 形式配置的加载,因此通过 AbstractXmlApplicationContext 来分析源码。

            AbstractApplicationContext#obtainFreshBeanFactory

                   -> AbstractRefreshableApplicationContext#refreshBeanFactory

                      --> AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)

        1.首先创建读取 BeanDefinition 的 BeanDefinitionReader 接口实现 XmlBeanDefinitionReader 实例,并设置环境信息。

        2.通过 BeanDefinitionReader  实现读取 BeanDefinition  配置信息。

复制代码

 1     /**
 2      * Loads the bean definitions via an XmlBeanDefinitionReader.
 3      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
 4      * @see #initBeanDefinitionReader
 5      * @see #loadBeanDefinitions
 6      */
 7     @Override
 8     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
 9         // Create a new XmlBeanDefinitionReader for the given BeanFactory.
10         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
11 
12         // Configure the bean definition reader with this context's
13         // resource loading environment.
14         beanDefinitionReader.setEnvironment(this.getEnvironment());
15         beanDefinitionReader.setResourceLoader(this);
16         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
17 
18         // Allow a subclass to provide custom initialization of the reader,
19         // then proceed with actually loading the bean definitions.
20         initBeanDefinitionReader(beanDefinitionReader);
21         loadBeanDefinitions(beanDefinitionReader);
22     }

复制代码

三. BeanDefinitionReader 读取,加载 BeanDefinition 配置分析

        AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)

              --> AbstractXmlApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader)

                      --> AbstractBeanDefinitionReader#loadBeanDefinitions(String, Set<Resource>)

                           --> XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)

                             --> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource )

         1.读取 XML 文件,获取到  Document 实例。为后续解析配置做准备。

         2.向 BeanFactory 中注册 BeanDefinition 配置信息。

           此处异常捕获比较多,学习异常规范处理。最底层的 Throwable 异常也捕获了,保证程序不会异常退出。

复制代码

 1     /**
 2      * Actually load bean definitions from the specified XML file.
 3      * @param inputSource the SAX InputSource to read from
 4      * @param resource the resource descriptor for the XML file
 5      * @return the number of bean definitions found
 6      * @throws BeanDefinitionStoreException in case of loading or parsing errors
 7      * @see #doLoadDocument
 8      * @see #registerBeanDefinitions
 9      */
10     protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
11             throws BeanDefinitionStoreException {
12 
13         try {
14             Document doc = doLoadDocument(inputSource, resource);
15             int count = registerBeanDefinitions(doc, resource);
16             if (logger.isDebugEnabled()) {
17                 logger.debug("Loaded " + count + " bean definitions from " + resource);
18             }
19             return count;
20         }
21         catch (BeanDefinitionStoreException ex) {
22             throw ex;
23         }
24         catch (SAXParseException ex) {
25             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
26                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
27         }
28         catch (SAXException ex) {
29             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
30                     "XML document from " + resource + " is invalid", ex);
31         }
32         catch (ParserConfigurationException ex) {
33             throw new BeanDefinitionStoreException(resource.getDescription(),
34                     "Parser configuration exception parsing XML from " + resource, ex);
35         }
36         catch (IOException ex) {
37             throw new BeanDefinitionStoreException(resource.getDescription(),
38                     "IOException parsing XML document from " + resource, ex);
39         }
40         catch (Throwable ex) {
41             throw new BeanDefinitionStoreException(resource.getDescription(),
42                     "Unexpected exception parsing XML document from " + resource, ex);
43         }
44     }

复制代码

 扫VX 领Java资料,前端,测试,python等等资料都有

四.BeanDefinitionDocumentReader 解析  BeanDefinition 配置分析

       (一) BeanDefinitionDocumentReader 分析

            XmlBeanDefinitionReader#doLoadBeanDefinitions

                 --> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)

                      -->  BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)

            1. 创建 BeanDefinitionDocumentReader  对象实例。

            2.创建 读取 BeanDefinition  配置信息Document的上下文(XmlReaderContext),为后续解析配置提供相关支持。

            3. 解析并注册Document 中配置的 BeanDefinition  信息。在 DefaultBeanDefinitionDocumentReader 实现具体逻辑。

复制代码

 1     /**
 2      * Register the bean definitions contained in the given DOM document.
 3      * Called by {@code loadBeanDefinitions}.
 4      * <p>Creates a new instance of the parser class and invokes
 5      * {@code registerBeanDefinitions} on it.
 6      * @param doc the DOM document
 7      * @param resource the resource descriptor (for context information)
 8      * @return the number of bean definitions found
 9      * @throws BeanDefinitionStoreException in case of parsing errors
10      * @see #loadBeanDefinitions
11      * @see #setDocumentReaderClass
12      * @see BeanDefinitionDocumentReader#registerBeanDefinitions
13      */
14     public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
15         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
16         int countBefore = getRegistry().getBeanDefinitionCount();
17         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
18         return getRegistry().getBeanDefinitionCount() - countBefore;
19     }

复制代码

       (二)BeanDefinitionDocumentReader 实现类 DefaultBeanDefinitionDocumentReader分析

        BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)

            -->  DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

                -->  DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

       1. 根据 ReaderContext 信息,创建对应的 实例。

       2. 检查 profile 配置信息。如果不匹配,则不解析当前root节点下的 BeanDefinition  配置。 

       3. 当前root节点 前置处理。

       4. 解析当前 root 节点的 BeanDefinition  配置信息。

       5. 当前root节点 后置处理。

    (三)   DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 分析

                DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

                        -->  DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 

                        -->  BeanDefinitionParserDelegate#parseCustomElement(Element)

         1. 判断 root 节点 DefaultNamespace 是否是 http://www.springframework.org/schema/beans 。

                 如果是,则遍历子节点进行解析。

                        当子节点 是 DefaultNamespace 。则使用  DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 解析节点。

                        否做使用  BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。

         2. 非默认 DefaultNamespace 值,则使用 BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。

                       例如 AOP 配置节点解析。例如:<aop:config>

                       事物配置节点解析。例如:<tx:annotation-driven proxy-target-class="true" />

       (四) 解析 DefaultNamespace 节点 BeanDefinition 信息。

              DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 

                       -->  DefaultBeanDefinitionDocumentReader#importBeanDefinitionResource(Element)

                       --> DefaultBeanDefinitionDocumentReader#processAliasRegistration(Element)

                       --> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

                       --> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

              1.依次解析 import  节点,alias 节点,bean节点, beans节点 定义的 BeanDefinition 信息。

       (五) 解析 非默认命名空间节点 BeanDefinition 信息。

                  BeanDefinitionParserDelegate#parseCustomElement(Element)

                       --> BeanDefinitionParserDelegate#parseCustomElement(Element, BeanDefinition)

                  1.获取节点命名空间。

                  2.根据命名空间获取对应的解析器。

                  3. 解析节点 BeanDefinition 信息。

复制代码

 1     /**
 2      * Parse a custom element (outside of the default namespace).
 3      * @param ele the element to parse
 4      * @param containingBd the containing bean definition (if any)
 5      * @return the resulting bean definition
 6      */
 7     @Nullable
 8     public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
 9         String namespaceUri = getNamespaceURI(ele);
10         if (namespaceUri == null) {
11             return null;
12         }
13         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
14         if (handler == null) {
15             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
16             return null;
17         }
18         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
19     }

复制代码

五.BeanDefinitionDocumentReader 解析  bean 节点

     XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)

           --> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource)

                 --> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)

                       --> DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document, XmlReaderContext)

                            --> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

                                 -->  DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element , BeanDefinitionParserDelegate)

                                       --> DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element, BeanDefinitionParserDelegate) 

                                             --> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

        

       1.使用 BeanDefinitionParserDelegate 解析 Bean 配置节点,得到保存 BeanDefinition 信息的辅助对象 BeanDefinitionHolder 实例。

       2.当 解析的 Bean 配置 BeanDefinitionHolder 实例不为空,则进行 Bean 配置 后续处理。

              a. 当 Bean 配置节点 找到 其他 Namespace 对应 处理器(NamespaceHandler),则进行特殊化处理。

              b. 向 BeanFactory 中注册解析成功的 BeanDefinition 定义。

              c.发送 BeanDefinition 解析成功事件 BeanComponentDefinition。

复制代码

 1     /**
 2      * Process the given bean element, parsing the bean definition
 3      * and registering it with the registry.
 4      */
 5     protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
 6         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 7         if (bdHolder != null) {
 8             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
 9             try {
10                 // Register the final decorated instance.
11                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
12             }
13             catch (BeanDefinitionStoreException ex) {
14                 getReaderContext().error("Failed to register bean definition with name '" +
15                         bdHolder.getBeanName() + "'", ele, ex);
16             }
17             // Send registration event.
18             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
19         }
20     }

复制代码

 

 扫VX 领Java资料,前端,测试,python等等资料都有

六. BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition) 解析  bean 节点

       DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

             --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element) 

                 --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element, BeanDefinition)

          1.解析 Element  元素的 id 和 name 属性,得到 beanName 和 aliases。

          2.检查 beanName 是否唯一。

          3. 创建 AbstractBeanDefinition 对象实例 bd ,并通过依次解析 Element  元素的属性给 bd 赋值。

             依次解析子节点 meta, lookup-method, replaced-method, constructor-arg, property, qualifier,并将解析后的值添加到 bd 相关变量。

             设置 bd 解析资源的相关信息。

          4. 如果 3 解析失败,则返回的 实例BeanDefinition 为 null,则这里也直接返回。

          5. 当上述步骤解析的 beanName 为 空时,使用指定方式生成 beanName。

                   当前 bean 是在其他Bean 内部时, 使用BeanDefinitionReaderUtils#generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean)   生成 beanName。

                   否则使用 XmlReaderContext 对应生成器生成 beanName。

          6.根据解析的 BeanDefinition 创建对应的 BeanDefinitionHolder 对象实例。

         

          在解析 bean 配置信息时,主要有如下 七个元数据包装类,对相关属性配置进行归档:

org.springframework.beans.factory.config.ConstructorArgumentValues  <constructor-arg>

org.springframework.beans.PropertyValue  <property>

org.springframework.beans.factory.support.ManagedArray     <array>

org.springframework.beans.factory.support.ManagedList        <list>

org.springframework.beans.factory.support.ManagedSet        <set>

org.springframework.beans.factory.support.ManagedMap       <map>

org.springframework.beans.factory.support.ManagedProperties   <props>

         每个配置具体字符串值对应了如下三种 处理类型: 

org.springframework.beans.factory.config.TypedStringValue   <value>

org.springframework.beans.factory.config.RuntimeBeanReference     <ref>

org.springframework.beans.factory.config.RuntimeBeanNameReference  <idref>

 View Code

 七.  BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)解析  bean 节点自定义属性

       DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

             --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element) 

                 --> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder)

                    --> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder, BeanDefinition)

                         -->  BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)

           1. 获得节点(Node) 的命名空间URI(NamespaceURI)。

           2. 如果命名空间URI不是默认的,则进行特殊处理。

           3. 通过 命名空间URI 到读取文件上下文(XmlReaderContext) 中查找对应 处理器(NamespaceHandler)。

                例如

                   Context的处理器: org.springframework.context.config.ContextNamespaceHandler

                        AOP的处理器:  org.springframework.aop.config.AopNamespaceHandler

              component的处理器: org.springframework.beans.factory.xml.ComponentNamespaceHandler

           4. 调用 NamespaceHandler#decorate(Node, BeanDefinitionHolder, ParserContext)方法解析 节点配置信息,并返回新的 BeanDefinitionHolder 实例。 

 View Code

 八. BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry) 向 BeanFactory 注册 BeanDefinition 实例信息

       1. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例。

       2. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例的别名列表。

 View Code

 扫VX 领Java资料,前端,测试,python等等资料都有

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值