一、什么是IOC
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的。从而降低解决问题的复杂度,而且可以灵活地被重用和扩展。IOC理论提出的观点大体是这样的:借助于”第三方“(对于Spring的IOC来说就是SpringIOC容器)实现具有依赖关系的对象之间的解耦,如下图。
通过将A、B、C、D四个对象放在IOC容器里,四个对象都只依赖于IOC容器,实现了四个对象之间的解耦。
在加入IOC容器之前,A对象如果需要B对象时需要先创建B对象A的创建依赖于B;而加入IOC容器之后,A需要B对象只要从IOC容器中取出B对象即可,IOC容器创建B对象并注入A对象即可。对于A对象来说由之间的被动变为了主动。
二、IOC的实现原理
IOC中最基本的技术就是“反射(Reflection)”编程,目前.Net C#、Java和PHP5等语言均支持,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
三、beanFactory和factoryBean
3.1beanFactory
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 行为.
总结:beanFactory是一个最基本的工厂类,它是IOC容器创建的工厂,通过不同的工厂实现,从不同的配置文件中获取配置生成对应的对象注入IOC容器。
3.2factoryBean
一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
总结:factoryBean是一个bean,它是Spring提供的一个工厂类接口;beanFactory是IOC容器的工厂而factoryBean是IOC容器内对象创建的工厂。
四、 BeanDefinition是什么,以及BeanDefinition加载机制
SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的,其继承体系如下:
Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:
4.1什么是BeanDefinition
BeanDefinition可以理解为一个Bean的配置文件类,BeanDefinition中有很多Bean的信息,例如类名、scope、属性、构造函数参数列表、依赖的bean、是否是单例类、是否是懒加载等,其实就是将Bean的定义信息存储到这个BeanDefinition相应的属性中,后面对Bean的操作就直接对BeanDefinition进行,例如拿到这个BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。
4.2BeanDefinition的加载
第一步:设置beanDefinitionReader为资源加载做准备。
在最终开始加载资源,会经过一系列繁琐的准备工作,核心加载逻辑在下一节doLoadBeanDefinitions加载逻辑实现描述,下面先是前期的准备工作:
在Spring初始化容器过程,第一步首先创建BeanFactory的时候,会调用AbstractApplicationContext的obtainFreshBeanFactory方法,里面会调用AbstractApplicationContext类中实现的refreshBeanFactory方法,在这个方法里,调用了loadBeanDefinitions(beanFactory)来解析BeanDefinition。
第二步:doLoadBeanDefinitions校验、解析xml文件流程
doLoadBeanDefinitions方法开始解析——》registerBeanDefinitions 解析文档创建BeanDefinition。
总结:创建BeanFactory时调用loadBeanDefinitions开始解析,然后再loadBeanDefinitions方法内调用doLoadBeanDefinitions通过解析器读取配置文件资源,然后调用registerBeanDefinitions注册BeanDefinitions完成Bean创建。