SpringIOC源码分析
更新日期:
Spring项目可以说是目前应用的比较广泛的一项开源项目。大多数的开发者应该都用过spring,spring中有两个很重要的概念就是IOC和AOP,今天我们就通过spring源码来分析一下SpringIOC的工作机制。
IOC简介
IoC是Inversion of Control的缩写,被翻译成控制反转。控制反转是Spring框架的核心。其原理是基于面向对象(OO)设计 原则的The Hollywood Principle:Don’t call us, we’ll call you(别找我,我会来找你的)。也就是说,所有的组件都 是被动的,所有的组件初始化和调用都由容器负责。组件处在一个容器当中,由容器负责管理。简单的来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控,即在一个类中调用另外一个类。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,即所谓反转。
Spring IOC体系结构
BeanFactory
Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:
其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。
BeanDefinition
SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的,其继承体系如下:
Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:
IOC容器的依赖注入
Spring中,依赖注入是在用户第一次向IOC容器索要Bean时触发的(通过getBean方法)。首先要得到BeanFactory通过getBeanFactory()方法。



然后调用getBean方法
在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中:
可以看到具体的注入过程转移到doGetBean(String…)中,在这个方法中,首先获取到Bean的名称(name):

主要的操作都是在BeanFactoryUtils这个工具类中完成。
然后它会根据beanName从缓存中取,
分支1:如果单例模式的bean已经被创建,则这种bean请求不需要重复的创建,调用:
跟踪进入getObjectForBeanInstance(…,null),
可以知道因为最后的RootBeanDefinition参数是null,所以执行的是:
而getCachedObjectForFactoryBean(beanName)中实现,其实现很简单,就是在缓存的bean map中查找bean返回。
获取到bean之后,让我们继续回到doGetBean(String…)方法中:
然后返回从spring IOC容器中获取到的bean。
分支2:缓存中没有正在创建的单态模式Bean,则执行以下分支:
缓存中已经有已经创建的原型模式Bean,但是由于循环引用的问题导致实例化对象失败。


然后,对IoC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找:
然后判断创建的Bean是否需要进行类型验证,一般不需要:
接下来,根据指定Bean名称获取其父级的Bean定义,主要解决Bean继承时子类合并父类公共属性问题:
取当前bean的所有依赖bean,这样就会触发getBean的递归调用,直至取到一个没有任何依赖的bean为止:
通过调用createBean来,创建单例bean的实例:
现在让我们继续看createBean(…),可以看到在AbstractBeanFactory中它只是个抽象类
具体的实现交给其子类(又见模板模式),进入子类AbstractAutowireCapableBeanFactory中看createBean的具体实现:
其具体的实现转到doCreateBean(String…),这个是真正创建bean的方法。这里我们看到与依赖注入关系比较密切的方法有createBeanInstance(创建实例对象)和populateBean(初始化对象,依赖注入)。
现在让我们进入到createBeanInstance()中进一步分析实例对象创建的过程:
在createBeanInstance中生成了Bean所包含的Java对象,这个对象的生成有很多不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,生成的方式由相关联的BeanDefinition来指定。
通过工厂方式实例化:
通过使用容器的自动装配进行实例化:
通过使用bean的构造函数实例化:
使用默认无参构造函数实例化:

因为getInstantiationStrategy()返回的默认的实例化策略,而默认的实例化策略是CglibSubclassingInstantiationStrategy,也即用cglib来对bean进行实例化。CGLIB是一个常用的字节码生成器的类库,它提供了一系列的API来提供Java的字节码生成和转换功能。
然后获取实例化对象的类型,调用PostProcessor后置处理器,向容器中缓存单态模式的Bean对象,以防循环引用等操作:

接下来对bean对象进行初始化,依赖注入在此触发。
定义一个exposedObject对象在初始化完成之后返回作为依赖注入完成后的Bean。

接下来让我们进入到populateBean()中分析对bean属性进行依赖注入的具体处理:
在populateBean()中,先是取得在BeanDefinition中设置的property值,这些property来自对BeanDefinition的解析,接着便开始进行依赖注入过程:
首先处理autowire自动装配的注入(根据bean名称,bean类型进行自动装配注入)
最后在通过applyPropertyValues对属性进行注入:
接着我们到applyPropertyValues中去看具体的对属性进行解析然后注入的过程,在其中会调用BeanDefinitionValueResolver对BeanDefinition进行解析:
接着为解析值创建一个拷贝,拷贝的数据将会被注入到bean中,它会先对PropertyValue判断,如果其没有经过转换则会调用resolveValueIfNecessary进行解析,然后注入到property中。
最后进行属性依赖注入: bw.setPropertyValues(new MutablePropertyValues(deepCopy));
下面到BeanDefinitionValueResolver中去看一下解析过程的实现,对属性进行解析的由resolveValueIfNecessary方法实现。在函数resolveValueIfNecessary中包含了所有对注入类型的处理,以RuntimeBeanReference(其是在对BeanDefinition进行解析时生成的数据对象)为例:

这就完成了resolve的过程,为依赖注入准备好了条件。
我们可以看出,对属性的注入过程分以下两种情况:
(1).属性值类型不需要转换时,不需要解析属性值,直接准备进行依赖注入。
(2).属性值需要进行类型转换时,如对其他对象的引用等,首先需要解析属性值,然后对解析后的属性值进行依赖注入。
对属性值的解析是在BeanDefinitionValueResolver类中的resolveValueIfNecessary方法中进行的,对属性值的依赖注入是通过bw.setPropertyValues方法实现的,在分析属性值的依赖注入之前,我们先分析一下对属性值的解析过程。
在doCreateBean中执行完populateBean,完成Bean的生成和依赖注入以后,开始对Bean进行初始化,这个初始化过程包含了对后置处理器的postProcessBeforeInitializtion回调,具体实现在initializeBean方法中: