spring原理分析(一)—spring-web环境的初始化

       今天我们要聊的是spring的基础模块bean的初始化。bean即java的对象,是一切程序的基础。bean的初始化主要将会涉及到spring的三个核心模块:Core、Context和Beans。

      java作为面向对象编程语言中的领导者,所有的设计思想根本上都是基于一个个鲜活的对象个体。就向我们了解的jvm中的新生的、老年代等等一样,java中的每个对象都是有生命的,生老病死在所难免。而如何让这一个个鲜活的个体有秩序的工作,并维护他们之间复杂的关系网,是一件让人头痛的事。spring的beans模块恰恰为我们解决的就是这部分问题。

spring原理分析(一)—spring-web环境的初始化_第1张图片

一、 先来谈谈spring-web的整体初始化流程

  spring解决上述问题正是通过beans、core和context(expression表达式模块这里没有算在内)三个模块来实现的。

      如上图,可以看出spring的相关核心的三个模块,如果把整个spring比做一个世界的话:

      (1)context作为整个应用的环境,spring通过他和整个web应用相关联,他通过 ContextLoaderListener监听器,获取整个web应用的相关的环境信息(ServletContext),加载对应spring内部定义的所有bean,并创造了所有bean的生活环境。  -----------即context就是这个社会环境。

      (2)beans相当于java应用的每个成员-----即这个社会中一个鲜活的生命

     (3)core相当于spring内部工具化的组件,包含了spring中核心的功能处理类。-------即社会上的各种工具。

首先我们来看下context和beans模块的整体类图:

spring原理分析(一)—spring-web环境的初始化_第2张图片

从中让我们抽出核心的几个处理类来:

spring原理分析(一)—spring-web环境的初始化_第3张图片

由上图,我们可以总结出简化版的总体时序图:


spring原理分析(一)—spring-web环境的初始化_第4张图片



    由此可以总起出spring-web的整体流程大概是:

        第一步:当web项目启动后,通过web.xml的配置的监听器ContextLoaderListener,开始加载整个spring环境。他首先生成xmlWebApplicationContext,目的是为了加载指定的applicationContext.xml文件,但显然这时候还并没有真正解析文件,因为spring中的bean之间会有这种各种各样的复杂关系、以及很多用户可扩展处,所以对于bean的加载,spring是通过工厂模式+描述定义的方式来实现。

         第二步:工厂即生成bean的源头,描述定义相当于对每个产品的设计图纸。因此此时首先要做的是先得有个工厂才行,所以通过AbstractApplicationContext的refreshBeanFactory的方法来建造,建造工厂的过程中将会同时通过加载xml文件生成所有需要初始化的单例bean的图纸(bean描述)。

        第三步:开始生产bean工厂中所有单例类,这个类制作过程中要考虑互相依赖、循环依赖、各种Processor和初始方法定义等,是一个很复杂的过程,下边会有相关介绍.

    根据上面的分析,我们基本已经了解spring的主体流程,对一些核心类有了大概了解。下面开始对spring的各个模块进行源码解析。

二 、context初始化

            context环境的初始化,是整个流程的起点。通过上面的分析我们已经知道,入口就是ContextLoaderListener。ContextLoaderListener中的初始化方法将会产生一个基于xml解析的context,此context有个DefaultListableBeanFactory工厂,这个工厂即当前环境下的bean工厂,核心代码包括:

  (1)调用ContextLoader.initWebApplicationContext(ServletContext servletContext)方法,进行初始化,

spring原理分析(一)—spring-web环境的初始化_第5张图片

        configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac,ServletContext sc)方法中如下


spring原理分析(一)—spring-web环境的初始化_第6张图片

ConfigurableWebApplicationContext的refresh()方法中将会进行整个bean环境的加载逻辑:

spring原理分析(一)—spring-web环境的初始化_第7张图片

  真正的bean初始逻辑主要在  ConfigurableWebApplicationContext.finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)方法中调用ConfigurableListableBeanFactory.preInstantiateSingletons()子方法,此方法中将会对单例bean进行处理:

spring原理分析(一)—spring-web环境的初始化_第8张图片

下面将会真正进入getBean的逻辑。

三、bean的初始化


接上文,bean的初始化将通过ConfigurableListableBeanFactory.preInstantiateSingletons中调用getBean获取对应实体,然后继续将会从AbstractBeanFactory的doGetBean(finalString name, finalClass requiredType, finalObject[] args, booleantypeCheckOnly)方法进行bean 的初始化,此时DefaultSingletonBeanRegistry中的几个属性是至关重要的:

spring原理分析(一)—spring-web环境的初始化_第9张图片

spring在初始bean时会利用这几个属性来解决循环依赖的问题,继续看doGetBean:

spring原理分析(一)—spring-web环境的初始化_第10张图片
图一
spring原理分析(一)—spring-web环境的初始化_第11张图片
图二

通过上边的实现,我们发现了两个getSingleton()方法,这正是实现bean初始化,同时解决循环依赖问题的关键:

(1)第一个getSingleton()方法是在进入doGetBean方法第一步开始调用,此时先尝试singletonObjects从读取bean,不存在尝试从singletonFactories中获取(注意如果此时工厂存在,代表此bean正在创建中),然后放到earlySingletonObjects中,供那些依赖于此bean的类使用,此时singletonFactories中将会清除此工厂,其使命已完成。

(2)第二个getSingleton()则是真正创建bean的地方,主要实现代码都在此时定义的singletonFactory的getObject()方法中,下面将会具体说明。

spring原理分析(一)—spring-web环境的初始化_第12张图片

下面为第二个getSingleton()方法的实现,可以看出spring初始化一个bean首先会先标记处此bean正在使用,初始化完后会移除此标记,重要的创建bean在工厂的getObject方法中:

spring原理分析(一)—spring-web环境的初始化_第13张图片

下面我们看看beanFacoty中都做了什么,查看源码,我们发现核心逻辑最后落到了AbstractAutowireCapableBeanFactory.doCreateBean(finalString beanName, finalRootBeanDefinition mbd, finalObject[] args)方法中:

spring原理分析(一)—spring-web环境的初始化_第14张图片

    此时需要的bean将会被创建。

     下面通过流程图,我们来回顾下bean的获取和循环依赖的解决方法:

假如此时有两个Bean:A和B,B是A中的一个属性,此时先初始A时:

spring原理分析(一)—spring-web环境的初始化_第15张图片

四、Ioc 容器的扩展点(此处摘录自文章三)

现在还有一个问题就是如何让这些 Bean 对象有一定的扩展性,就是可以加入用户的一些操作。那么有哪些扩展点呢? Spring 又是如何调用到这些扩展点的?

对 Spring 的 Ioc 容器来说,主要有这么几个。BeanFactoryPostProcessor, BeanPostProcessor。他们分别是在构建 BeanFactory 和构建 Bean 对象时调用。还有就是 InitializingBean 和 DisposableBean 他们分别是在 Bean 实例创建和销毁时被调用。用户可以实现这些接口中定义的方法,Spring 就会在适当的时候调用他们。还有一个是 FactoryBean 他是个特殊的 Bean,这个 Bean 可以被用户更多的控制。

这些扩展点通常也是我们使用 Spring 来完成我们特定任务的地方,如何精通 Spring 就看你有没有掌握好 Spring 有哪些扩展点,并且如何使用他们,要知道如何使用他们就必须了解他们内在的机理。可以用下面一个比喻来解释。

我们把 Ioc 容器比作一个箱子,这个箱子里有若干个球的模子,可以用这些模子来造很多种不同的球,还有一个造这些球模的机器,这个机器可以产生球模。那么他们的对应关系就是 BeanFactory 就是那个造球模的机器,球模就是 Bean,而球模造出来的球就是 Bean 的实例。那前面所说的几个扩展点又在什么地方呢? BeanFactoryPostProcessor 对应到当造球模被造出来时,你将有机会可以对其做出设当的修正,也就是他可以帮你修改球模。而 InitializingBean 和 DisposableBean 是在球模造球的开始和结束阶段,你可以完成一些预备和扫尾工作。BeanPostProcessor 就可以让你对球模造出来的球做出适当的修正。最后还有一个 FactoryBean,它可是一个神奇的球模。这个球模不是预先就定型了,而是由你来给他确定它的形状,既然你可以确定这个球模型的形状,当然他造出来的球肯定就是你想要的球了,这样在这个箱子里尼可以发现所有你想要的球

通过上面的分析我们能初步了解spring的整体流程,具体细节还需对照源码仔细分析,下面列出几篇文章,有更加详细的流程进行代码分析:

(1)https://www.iflym.com/index.php/code/201208280001.html

(2)https://www.iflym.com/index.php/code/201208290001.html

(3)https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/

你可能感兴趣的:(spring原理分析(一)—spring-web环境的初始化)