Spring 深入——IoC 容器 02

IoC容器的实现学习——02目录

  • IoC容器的实现学习——02
    • 回顾
    • IoC 容器的初始化过程:
      • BeanDefinition 的 Resource 定位
        • 小结:
回顾前面学习了 IoC 模式的核心概念,使用场景 , 以及 Spring 对 IoC
具体实现的两种系列:BeanFactory 和 ApplicationContext
通过两种系列的具体 IoC 容器来帮助我们了解了两个不同的特点 , 以及面向不同的场景 。有利有弊,在开发中需要根据具体需求选择合适的 IoC 具体实现 。
其中也通过对 Spring IoC 的具体实现的简单分析,对 IoC 设计的有了初步的了解和想法 。那么现在就来开始了解 IoC 容器初始化的过程 。
IoC 容器的初始化过程:前面在学习 FileSystemXmlApplicationContext 的时候,构造方法中通过此类调用了 refresh() 方法 。IoC 容器的初始化实际上就是通过这个方法来启动的,标志着 IoC 容器正式启动 。
IoC 容器的启动包括以下三个基本过程:
  1. BeanDefinition 资源的定位
  2. ~ 的载入
  3. ~ 的注册
期间需要注意的是这是一个顺序过程,同时指的是 IoC 容器的初始化,而 Bean 的依赖注入的实现 , 一般不包括其中,但是 BeanDefiniton 有一个 lazyinit 的属性,用户可以通过这个属性改变 Bean 的依赖注入过程,eg:一般情况下 Bean 的注入需要在容器初始化之后,第一次调用 getBean() 时才会触发 , 而通过 lazyinit 属性可以让 Bean 在 IoC 容器初始化时就预先完成了依赖注入 。
BeanDefinition 的 Resource 定位根据前面的学习 , 我们这一过程的表层应该不难知晓,就是通过定义一个 Resuorce 去定位容器使用的 BeanDefinition 。eg:ClassPathResource() 这个类就是在项目中的类路径中寻找以文件形式存在的 BeanDefinition 。
应该注意的是,不能把 Resource 的定位 BeanDefinition 资源和 BD 的载入弄混淆了 。只是定位资源而已,此时 IoC 容器还不能直接使用这些信息,这些信息是交由 BeanDefinitionReader 来对这些信息进行 BD 的载入处理 。
相对于 DefaultListableBeanFactory 容器需要手动配置好特定的 Resource 读取器,ApplicationContext 容器就准备好了一系列的读取器 。
但是使用 DefaultListableBeanFactory 这种底层容器可以根据业务定制 IoC 容器的灵活性,有利有弊 。
还是通过 FileSystemXmlApplicationContext 这一具体容器来分析是如何完成 Resource 的定位过程 。
继承体系:
Spring 深入——IoC 容器 02

文章插图
主要两个功能的源码:
Spring 深入——IoC 容器 02

文章插图
上图表明了getResourceByPath()是实现 Resource 定位的方法 。但是并不是使用者调用的,查看该方法的调用链:
Spring 深入——IoC 容器 02

文章插图
上图标注了该方法最初是由 refresh() 方法触发的,而 refresh() 是在构造器中调用的 。
我们需要通过这个方法来了解过程 。
构造器调用的是超类 AbstractApplicationContext 中的 refresh(),查看源码:
public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {this.prepareRefresh();// 创建beanFactory以及扫描bean信息(beanDefinition) , 并通过BeanDefinitionRegistry 注册到容器中 。ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();// 省略...}}obtainFreshBeanFactory() 源码:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();// 省略...}refreshBeanFactory() 是一个抽象方法,有两个具体的实现类:
  • AbstractRefreshableApplicationContext
  • GenericApplicationContext
在这里我们的 FSXAC 继承了 AbstractRefreshableApplicationContext,所以我们看在这个类中 refreshBeanFactory() 的实现:
protected final void refreshBeanFactory() throws BeansException {//...try {DefaultListableBeanFactory beanFactory = this.createBeanFactory(); // 1beanFactory.setSerializationId(this.getId());this.customizeBeanFactory(beanFactory);this.loadBeanDefinitions(beanFactory);// 2///...}}我们抽出这两行代码进行分析:
  1. 创建 BeanFactory,以 DefaultListableBeanFactory 作为 IoC 容器 。
  2. BD 的载入相关启动 。
我们到目前位置并没有看到与之相关的 Resource 定位信息,只看到 BD 的载入启动,所以针对

推荐阅读