专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Spring IoC 源码之XmlBeanFactory

失宠的 XmlBeanFactory

121_1.png  上篇文章中提到 Spring IoC 容器中的两条设计路径,但是这两条路径都只是体现了接口之间的关系,今天就从具体的实现来看看 Spring IoC 不同功能的IoC容器。

  在Spirng 中IoC容器的实现有很多种,XmlBeanFactorySpring中最早提供的实现类,虽然现在已经废弃不用了,但是依旧可以从中学习到很多的东西。面对过去,知其所以然;面向未来,才能更好的运用。

XmlBeanFactory的使用

  由于XmlBeanFactory已经弃用,这里简单的使用一下,代码展示如下:

public class XmlBeanFactoryTest {
   public static void main(String[] args) {
      BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-bean.xml"));
      XmlBeanFactoryService xmlServiceTest = (XmlBeanFactoryService)bf.getBean("xmlServiceTest");
      xmlServiceTest.say();
   }
}

public class XmlBeanFactoryService {

   public void say(){
      System.out.println("hello");
   }
}

  XmlBeanFactory的使用是通过通过在xml文件中配置相应的Bean,然后通过加载xml文件,根据id来获取相应的Bean,xml的配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="classPathAppContextService" class="com.fchen.service.ClassPathAppContextService">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="xmlServiceTest" class="com.fchen.service.XmlBeanFactoryService">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
</beans>

XmlBeanFactory的设计路径

Spring IoC总览中,提到了两种IoC容器的设计路径,其中XmlBeanFactory 隶属于: BeanFactoryHierarchicalBeanFactory,再到 ConfigurableBeanFactory。这一条设计路线,通过下面类设计的关系图可知:

121_2.png

  从上图中可知 XmlBeanFactoryDefaultListableBeanFactory 的基础上做了扩展,而 DefaultListableBeanFactory 则实现了 ConfigurableBeanFactory。这里这个DefaultListableBeanFactory 是在Spring IoC 容器设计中极其重要的实现类,其中包含了IoC容器所具有的功能。后续的文章中会做详细的介绍。

XmlBeanFactory的源码分析

public class XmlBeanFactory extends DefaultListableBeanFactory {

  /**
     * 初始化 XmlBeanDefinitionReader 对象
     * 处理以 xml 方式定义的 BeanDefinition
     */
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        /** 调用父类的构造方法*/
        super(parentBeanFactory);
        /** 使用 XmlBeanDefinitionReader,调用loadBeanDefinitions*/
        this.reader.loadBeanDefinitions(resource);
    }

}

  从上述源码来看,XmlBeanFactory 只提供了最基本的IoC容器的功能,他用来读取以 XML的方式描述的SpringBean的定义(BeanDefinition)。通过下图 XmlBeanFactory的类继承关系图,来分析上述源码:

121_3.png   XmlBeanFactory 继承自 DefaultListableBeanFactory ,可知 XmlBeanFactory 会拥有父类的功能。在 XmlBeanFactory中定义并初始化了 XmlBeanDefinitionReader对象,并通过它来完成 Bean描述文件的读取。

XmlBeanDefinitionReader对象

121_4.png

  • 1.通过继承AbstractBeanDefinitionReader 中的方法,来使用 ResourceLoader 将资源文件路径转换 为对应的Resource 文件。
  • 2.通过DocumentLoader 对 Resource 文件进行转换,将Resource文件转换为 Document 文件。
  • 3.通过实现BeanDefinitionDocumentReader 接口的 DefaultBeanDefinitionDocumentReader类, 对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析。

XmlBeanFactory 的初始化

  在自己写的测试方法中,从下面这一行代码开始

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-bean.xml"));

121_5.png  构造XmlBeanFactory这个IoC容器时,需要指定的BeanDefinition的信息来源,而这个信息 来源需要封装成Spring的Resource类来给出。Resource是Spring用来封装I/O操作的类。然后将Resource作为 构造参数传递给XmlBeanFactory构造函数。这样,IoC容器就可以方便定位到需要的BeanDefinition信息来对Bean 完成容器的初始化和依赖注入过程。

  对XMLBeanDefinitionReader对象的初始化,以及使用这个对象来完成loadBeanDefinitions的 调用,就是这个调用启动从Resource中加载BeanDefinition的过程,loadBeanDefinitions()同时也是IoC容器 初始化的重要组成部分。

注: 这里请记住 loadBeanDefinitions() 这个方法,在以后的有关IoC的其他实现类中,Spring不只一次的用到这个方法。

XmlBeanFactory中的两行代码

  对于XmlBeaFactory的调用最后都是通过super(parentBeanFactory);this.reader.loadBeanDefinitions(resource);来完成上述的功能。 下面,就来看一下这两行代码都做了些什么事情。

1.super(parentBeanFactory)

  代码的调用顺序,结合XmlBeanFactory的类关系的继承图,可以看到其调用顺序如下:

①: XmlBeanFactory#super(parentBeanFactory) 其中parentBeanFactory 为null;

②: DefaultListableBeanFactory#super(null)

③: AbstractAutowireCapableBeanFactory#this()

④: AbstractAutowireCapableBeanFactory#super() 这里会调用 ignoreDependencyInterface()相关的方法

⑤: AbstractBeanFactory() 调用AbstractBeanFactory 的无惨构造方法

  这里创建的XmlBeanFactory在继承了DefaultListableBeanFactory容器的功能的同时,增加了新的功能。

2.this.reader.loadBeanDefinitions(resource)

  下面重点看一下loadBeanDefinitions()的调用顺序,因为涉及到的代码太多,这里只是简单标注调用逻辑,以及会画出相关的时序图。代码的讲解后面的文章会分析到,或在github上下载自行查看。

①: XmlBeanDefinitionReader#loadBeanDefinitions(Resource resource)

②: XmlBeanDefinitionReader#loadBeanDefinitions(new EncodedResource(resource))

a: EncodedResource()#this(resource, null, null)

b: EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset)

c: Object()

③: XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource encodedResource)

a: encodedResource.getResource().getInputStream()

④: XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource)

⑤: XmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource)

⑥: XmlBeanDefinitionReader#createBeanDefinitionDocumentReader()

⑦: DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

⑧: DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element root)

⑨: DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

⑩: BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element)

⑪: DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

⑫: DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

⑬: BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

⑭: DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

⑮: DefaultListableBeanFactory#beanDefinitionMap.put(beanName, beanDefinition)

3.loadBeanDefinitions(resource)时序图

121_6.png

总结

  XmlBeanFactory是IoC容器最底层的实现,从上面的分析过程可以看到,IoC容器的启动包括以下的三个过程,具体来说,这个启动包括BeanDefinition的Resource定位、载入和注册三个过程。

  第一个过程是Resource定位过程。这个Resource定位指的是BeanDefinition的资源定位,它由 ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式BeanDefinition的使用都提供统 一的接口。

  第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IoC容器内部的 数据结构,而这个容器内部的数据结构就是BeanDefinition。

  第三个过程是向IoC容器注册这些BeanDefinition的过程。这个过程调用BeanDefinitionRegistry 接口的实现来完成。这个注册过程把载入过程中的解析得到的BeanDefinition向IoC容器进行注册。就是在IoC容器内部 将BeanDefinition注入到一个HashMap中去,IoC容器就是通过这个HashMap来保存BeanDefinition的数据。


个人微信公众号:

121_7.png个人github: github.com/FunCheney

文章永久链接:https://tech.souyunku.com/28093

未经允许不得转载:搜云库技术团队 » Spring IoC 源码之XmlBeanFactory

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们