一、IoC原理
1、哪些方面的控制被反转了?
依赖对象的获得被反转了,所以依赖反转也被称为“依赖注入”。
2、通常是两个或者多个对象合作完成业务逻辑,因此每个对象都需要其合作者的对象的引用,如果这个过程让对象自己实现,讲导致代码高度耦合并难以测试。控制反转是关于一个对象如何获得它所依赖的对象的引用的,这里的反转是责任的反转。
将这种依赖注入的职责从对象手中移除,交给框架来进行,将会在解耦代码的同时提高代码的可测试性。
3、把依赖的控制权从具体业务对象手中转交给平台或框架中,是降低面向对象系统设计复杂性和提高面向对象系统可测试性的一个有效的解决方案。
二、Spring IoC容器的主要特征
Spring IoC容器根据控制反转原理,实现了Bean的自动装配,并负责Bean生命周期的管理。
主要步骤:
1、IoC 容器的初始化
这个过程的目的是将Bean信息维护到容器中,主要分为三个子步骤:
【】、BeanDefinition资源的定位
这个步骤找到用户定义的Bean的资源位置,比如配置文件、注解等;
【】、BeanDefinition的载入
这个步骤将定位到的资源加载、解析到容器中,并存储在BeanDefinition结构中;
【】、BeanDefinition的注册
这个步骤将解析得到的所有BeanDefinition结构注入到一个HashMap中,方便通过getBean使用。
2、IoC容器的依赖注入
这个过程主要完成Bean的创建和依赖关系建立,主要是通过getBean方法触发的,对于每个getBean调用,不要分为两个子步骤完成依赖注入:
【】、createBeanInstance方法
生成Bean所包含的Java对象,方法之一是使用CGLIB对Bean进行实例化
【】、populateBean方法:
依据BeanDefinition信息,完成属性解析和真正的依赖注入。
注意:在Bean的创建和对象依赖注入的过程中, 需要依据BeanDefinition中的信息来递归地完成依赖注入,一个递归是在上下文体系中查找需要的Bean和创建Bean的递归调用,另一个递归是在依赖注入时,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。
三、IoC容器的其他特征
1、ApplicationContext和Bean的初始化和销毁
IoC容器自身也有一个初始化和销毁关闭的过程。ApplicationContext的初始化启动过程是在AbstractApplicationContext中实现的。主要在prepareBeanFactory()方法中做一些准备工作,在这个方法中,为容器配置了ClassLoader、PropertyEditor和BeanPostProcessor等。
IoC容器的关闭工作,在doClose()方法中完成,在这个方法中先发出容器关闭的信号,然后将Bean逐个关闭,最后关闭容器自身。
Spring IoC实现了Bean的生命周期管理,Bean的初始化和销毁都在这个管理中控制。在管理时提供了Bean生命周期各个时间点的回调。
Bean的生命周期包括以下几个阶段:
* Bean实例的创建;
* 为Bean实例设置属性;
* 调用Bean的初始化方法;
* 应用可以通过IoC容器使用Bean;
* 当容器关闭时,调用Bean的销毁方法;
Bean的初始化方法调用是在initializeBean方法中实现的:调用invokeInitMethods方法。先判断Bean是否实现了InitializingBean接口,如果实现了就调用该接口的afterPropertiesSet方法(这是Bean实现的初始化处理),然后判断Bean是否配置了initMethod,如果有,就通过invokeCustomInitMethod方法来直接调用,最终完成Bean的初始化。
在容器关闭时,完成对Bean的销毁方法的调用,是在destory方法中处理的,可以在DisposableBeanAdapter类中看到该方法的实现。该方法中,先遍历调用注入的BeanPostProcessor的postProcessBeforeDestruction方法,然后判断Bean是否实现了DisposableBean接口,如果实现了该接口就调用该bean的destory()方法,然后如果bean配置了销毁方法,就执行invokeCustomDestoryMethod()方法来调用销毁方法。
2、lazy-init属性和预实例化
正常的Bean的依赖注入是发生在应用第一次向容器索要Bean时完成的。但有一种例外情况,用户可以设置Bean的lazy-init属性来控制预实例化的过程,即在初始化容器时完成Bean的依赖注入。
在AbstractApplicationContext中refresh方法,调用finishBeanFactoryInitialization方法,该方法封装了对lazy-init属性的处理,实际处理是在DefaultListableBeanFactory的preInstantiateSingletons方法中完成的。该方法对单例Bean完成预实例化。这里也是直接通过getBean触发依赖注入的,和普通的依赖注入相比,只是触发的时间和方式不同。
3、FactoryBean的实现
FactoryBean是充当Bean工厂类的作用,在getBean中起作用,getBean方法中调用getObjectForBeanInstance(), 在该方法中又会触发对getObjectFromFactoryBean方法的调用,接着触发doGetObjectFromFactoryBean方法调用,在doGetObjectFactoryVBean方法中执行object = factory.getObject(),获得bean对象。
FactoryBean类似于AbstractFactory抽象工厂,getObjectForBeanInstance()方法类似于createProductA()这样的生产接口,而TransactionProxyFactoryBean,就是具体的工厂实现,其生产TransactionProxy就是“抽象工厂”模式中对应的ConcreteProduct。
4、BeanPostProcessor的实现
BeanPostProcessor是Bean的后置处理器,可以监听容器触发的事件。BeanPostProcessor是一个接口类,有两个接口方法,postProcessBeforeInitialization方法和postProcessAfterInitialization方法。postProcessBeforeInitialization方法在Bean的初始化调用之前提供回调入口,postProcessAfterInitialization方法在Bean的初始化后提供回调入口。 用户需要关系这些事件,只需实现BeanPostProcessor接口类,并配置对应的bean(注解形式或配置文件)即可。
我们知道在populateBean方法中完成了Bean的依赖注入,postProcessBeforeInitialization方法是在populateBean方法调用完成之后被调用的,具体是在initializeBean方法中调用的,如下:
在InitializeBean方法中,先是处理Aware相关的监听(后面再分析),然后是对postProcessBeforeInitialization方法、初始化方法、postProcessAfterInitialization方法的回调,最后才得到可以正常使用的Bean。
下面是applyBeanPostProcessorsBeforeInitialization方法和applyBeanPostProcessorsAfterInitialization方法的内容:
5、autowiring自动装配的实现
在自动装配中,不需要对Bean属性做显式的依赖关系声明,只需要配置好autowiring属性,IoC容器会根据这个属性的配置,使用反射自动查找属性的类型或者名字,然后基于属性的类型或名字来自动匹配IoC容器中的Bean,从而自动地完成依赖注入。自动装配属于依赖注入的方式,当然也是在populateBean中实现的,可以参看AbstractAutowireCapableBeanFactory的populateBean方法和autowiring实现相关的部分。
对autowiring属性的处理,调用的相应是autowireByName方法和autowireByType方法,如下:
以autowireByName为例,看自动装配功能是怎么实现的,对autowireByName来说,它先需要得到当前Bean的属性名(在BeanWrapper和BeanDefinition中封装好了),然后是对一系列属性名进行匹配,在匹配的过程中直接使用属性名字向容器索取Bean,也就是getBean方法。然后完成依赖注入。
6、Bean的依赖检查
通常Bean的依赖注入发生在应用第一次向容器索取Bean时,这时并不能保证注入一定能够成功,如果需要重新检查这些依赖关系的有效性,会很繁琐。因此Spring IoC容器设计了一个依赖检查特性,可以检查bean的所有属性是否都已经被正确设置了。
具体使用是应用只需要在Bean定义中设置dependency-check属性来指定依赖检查模式即可,可以将属性设置为none、simple、object、all四种模式。默认的模式是none。
7、Bean对IoC容器的感知
如果需要在 Bean中直接对IoC容器进行操作,需要使用Spring IoC容器的Bean对容器感知的功能,它是通过aware接口来完成 的,有以下这些:
【】BeanNameAware:可以在Bean中得到它在IoC容器中的Bean实例名称;
【】BeanFactoryAware:可以在Bean中 得到Bean所在的IoC容器,从而直接在Bean中使用IoC容器的服务;
【】ApplicationContextAware:可以在Bean中得到Bean所在的应用上下文,从而直接在Bean中使用应用上下文的服务;
【】MessageSourceAware:可以在Bean中得到消息源;
【】ApplicationEventPublisherAware:在Bean中得到应用上下文的事件发布器;
【】ResourceLoaderAware:可以在Bean中得到ResourceLoader,从而在Bean中使用ResourceLoader加载外部对应的Resource资源。
以ApplicationContextAware为例,用户需要 实现ApplicationContextAware接口,在setApplicationContext(ApplicationContext applicationContext) 中保存applicationContext引用。这个setApplicationContext方法会被Spring IoC容器完成回调。具体的回调机制如下:ApplicationContextAwareProcessor作为BeanPostProcessor的实现。当用户的实现了对应Aware的Bean在完成依赖注入之后,AwareProcessor作为实现Aware的Bean的后置处理器被调用,然后在postProcessBeforeInitialization方法中回调Bean中的诸如setApplicationContext这样的方法。
上述代码可以看出,如果当前初始化的bean是Aware类型的bean,就为该bean注入对应的感知信息。
从上述代码可以看出,在Aware Bean的后置处理器AwareProcessor中,确实回调了用户Aware Bean中实现的Aware接口,因此使用户Bean具有感知Spring IoC的能力。