Spring IoC原理分析

问题

要想使用Spring IoC,必须要创建Spring IoC容器。
那么什么是IoC容器呢?
如何创建IoC容器呢?
IoC容器是如何初始化Bean实例的呢?

什么是IoC容器?

什么是IoC容器?

所谓的IoC容器就是指的Spring中Bean工厂里面的Map存储结构(存储了Bean的实例)。

Spring框架中的工厂有哪些?

ApplicationContext接口()
基于了BeanFactory接口,并提供应用框架级别服务
实现ApplicationContext接口的工厂,可以获取到容器中具体的Bean对象
BeanFactory工厂(是Spring框架早期的创建Bean对象的工厂接口)
实现BeanFactory接口的工厂也可以获取到Bean对象,提供了基本的DI支持
其实通过源码分析,不管是BeanFactory还是ApplicationContext,其实最终的底层BeanFactory都是DefaultListableBeanFactory

ApplicationContext和BeanFactory的区别?

创建Bean对象的时机不同:
BeanFactory采取延迟加载,第一次getBean时才会初始化Bean。
ApplicationContext是加载完applicationContext.xml时,就创建具体的Bean对象的实例。(只对BeanDefition中描述为是单例的bean,才进行饿汉式加载

Spring IoC原理分析

Spring IoC原理分析

如何创建Web环境中的IoC容器?

创建方式

  • ApplicationContext接口常用实现类

ClassPathXmlApplicationContext:
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
AnnotationConfigApplicationContext:
当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

  • Java应用中创建IoC容器:(了解)

ApplicationContext context = new ClassPathXmlApplicationContext(xml路径);

  • Web应用中创建IoC容器:(重点)

web.xml中配置ContextLoaderListener接口,并配置ContextConfigLocation参数
web容器启动之后加载web.xml,此时加载ContextLoaderListener监听器(实现了ServletContextListener接口,该接口的描述请见下面《三类八种监听器》)
ContextLoaderListener监听器会在web容器启动的时候,触发contextInitialized()方法。
contextInitialized()方法会调用
initWebApplicationContext()方法,该方法负责创建Spring容器(DefaultListableBeanFactory)

Spring IoC原理分析

源码分析

  1. web服务器(tomcat)启动会加载web.xml(启动ContextLoaderListener监听器)

Spring IoC原理分析

  1. 调用ContextLoaderListener类的contextInitializd方法,创建Web环境中的Spring上下文对象。

Spring IoC原理分析

  1. ContextLoader类中创建Spring容器并初始化容器中的Bean实例
    Spring IoC原理分析
  2. 继续调用ContextLoader类的configureAndRefreshWebApplicationContext方法,该方法中调用最终初始化Bean的refresh方法

Spring IoC原理分析
图示:
该图示主要是分析上面第三步中【创建Spring容器】的图示
Spring IoC原理分析

spring容器初始化源码分析

容器初始化主流程分析

  • 主流程入口:

ApplicationContext context = new ClassPathXmlApplicationContext(“spring.xml”)

  • ClassPathXmlApplicationContext类:重载的构造方法依次调用,进入下面代码
    Spring IoC原理分析
  • AbstractApplicationContext的refresh方法:初始化spring容器的核心代码
    Spring IoC原理分析
  • 图示
    Spring IoC原理分析

创建BeanFactory流程分析

获取新的BeanFactory子流程

  • 子流程入口(从主流程refresh方法中的第二步开始)
    Spring IoC原理分析
  • 调用AbstractApplicationContext中的obtainFreshBeanFactory方法
    Spring IoC原理分析
  • 调用AbstractRefreshableApplicationContext的refreshBeanFactory方法
    Spring IoC原理分析

加载解析BeanDefinition子流程(loadDefinitions方法)

源码分析
  • 子流程入口(AbstractRefreshableApplicationContext类的方法)
    Spring IoC原理分析

  • 此处依次调用多个类的loadBeanDefinitions方法(AbstractXmlApplicationContext
    AbstractBeanDefinitionReader
    XmlBeanDefinitionReader),一直调用到XmlBeanDefinitionReader
    类的doLoadBeanDefinitions方法
    Spring IoC原理分析

  • 对于doLoadDocument方法不是我们关注的重点,我们进入到该类的registerBeanDefinitions方法看看
    Spring IoC原理分析

  • 此处有两个地方是我们关注的:一个createRederContext方法,一个是DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法,先进入createRederContext方法看看
    Spring IoC原理分析

  • 至此,14个NamespaceHandlerResolver初始化成功。然后我们再进入DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法
    Spring IoC原理分析

  • 继续进入到该类的doRegisterBeanDefinitions方法看看,这是真正干活的方法
    Spring IoC原理分析

  • 继续进入parseBeanDefinitions方法

  • Spring IoC原理分析

  • 我们看到有两种解析方案,先看看parseDefaultElement方法
    Spring IoC原理分析

  • 不过我们重点看看BeanDefinitionParserDelegate类的parseCustomElement方法(AOP标签、tx标签的解析都是在该步骤中完成的)
    Spring IoC原理分析

  • getNamespaceURI方法的作用一目了然,我们就不去追踪了,接下来我们进入DefaultNamespaceHandlerResolver类的resolve方法看看:
    Spring IoC原理分析

  • 在上面代码中,我们看到了一行代码:namespaceHandler.init();这个方法是很重要的。它实现了自定义标签到处理类的注册工作,不过NamespaceHandler是一个接口,具体的init方法需要不同的实现类进行实现,我们通过AopNamespaceHandler了解一下init的作用,其中aop:config标签是由ConfigBeanDefinitionParser类进行处理:
    Spring IoC原理分析

  • 至此,我们了解到了xml中的aop标签都是由哪些类进行处理的了。不过init方法只是注册了标签和处理类的对应关系,那么什么时候调用处理类进行解析的呢?我们再回到BeanDefinitionParserDelegate类的parseCustomElement方法看看
    Spring IoC原理分析

  • 我们看到,最后一行执行了parse方法,那么parse方法,在哪呢?我们需要到NamespaceHandlerSupport类中去看看,它是实现NamespaceHandler接口的,并且AopNamespaceHandler是继承了NamespaceHandlerSupport类,那么该方法也会继承到AopNamespaceHandler类中。
    Spring IoC原理分析

  • 至此,整个XML文档的解析工作,包括bean标签以及自定义标签如何解析为BeanDefinition信息的过程,我们已经了解了。

  • 后续具体想了解哪个自定义标签的处理逻辑,可以自行去查找xxxNamespaceHandler类进行分析。

图示

Spring IoC原理分析

创建Bean流程分析

  • 子流程入口
    Spring IoC原理分析

  • 我们进入finishBeanFactoryInitialization方法看看:
    Spring IoC原理分析

  • 继续进入DefaultListableBeanFactory类的preInstantiateSingletons方法,我们找到下面部分的代码,看到工厂Bean或者普通Bean,最终都是通过getBean的方法获取实例的。
    Spring IoC原理分析

  • 继续跟踪下去,我们进入到了AbstractBeanFactory类的doGetBean方法,这个方法中的代码很多,我们直接找到核心部分:
    Spring IoC原理分析

  • 接着进入到AbstractAutowireCapableBeanFactory类的方法,找到以下代码部分
    Spring IoC原理分析

  • 我们终于找到核心的地方了,进入doCreateBean方法看看,该方法我们关注两块重点区域
    Spring IoC原理分析
    Spring IoC原理分析

  • 对于如何创建Bean的实例,和填充属性,暂时先不去追踪了,我们先去看看initializeBean方法是如何调用BeanPostProcessor的,因为这个牵扯到我们对于AOP动态代理的理解。
    Spring IoC原理分析

  • 至此,如何创建Bean,以及AOP在哪产生代理的步骤,我们已经分析过了。