spring IOC源码分析(3)
1.IOC容器的依赖注入
Spring中,依赖注入是在用户第一次向IOC容器索要Bean时触发的(通过getBean方法)。

在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中:
- public Object getBean(String name) throws BeansException {
- return doGetBean(name, null, null, false);
- }
可以看到具体的注入过程转移到doGetBean(String…)中,在这个方法中,它首先从缓存中取,如果单件模式的bean已经被创建,则这种bean请求不需要重复的创建,调用
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
跟踪进入getObjectForBeanInstance(…,null),可以知道因为最后的RootBeanDefinition参数是null,所以执行的是:
- if (mbd == null) {
- object = getCachedObjectForFactoryBean(beanName);
- }
而getCachedObjectForFactoryBean(beanName)中实现,其实现很简单,就是在缓存的bean map中查找bean返回。
继续回到doGetBean(String…)方法中:
- //取当前bean的所有依赖bean,这样就会触发getBean的递归调用,直至取到一个没有任何依赖的bean为止
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (String dependsOnBean : dependsOn) {
- getBean(dependsOnBean);
- //注册依赖的bean实例,具体实现过程在DefaultSingletonBeanRegistry中实现,其实就是将依赖的bean添加到依赖的hashmap中
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- //通过调用createBean来,创建单例bean的实例
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- //同样调用createBean创建prototype的bean实例
- else if (mbd.isPrototype()) {
- // It's a prototype -> create a new instance.
- Object prototypeInstance = null;
- try {
- beforePrototypeCreation(beanName);
- prototypeInstance = createBean(beanName, mbd, args);
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- bean=getObjectForBeanInstance(prototypeInstance,name, beanName, mbd);
- }
继续看createBean(…),可以看到在AbstractBeanFactory中它只是个抽象类,具体的实现交给其子类(又见模板模式),进入子类AbstractAutowireCapableBeanFactory中看createBean的具体实现:
- Object beanInstance = doCreateBean(beanName, mbd, args);
其具体的实现转到doCreateBean(String…),这里我们看到与依赖注入关系比较密切的方法有createBeanInstance和populateBean。
- BeanWrapper instanceWrapper = null;
- if (mbd.isSingleton()) {
- instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
- }
- if (instanceWrapper == null) {
- instanceWrapper = createBeanInstance(beanName, mbd, args);
- }
- // Initialize the bean instance.
- Object exposedObject = bean;
- try {
- populateBean(beanName, mbd, instanceWrapper);
- if (exposedObject != null) {
- exposedObject = initializeBean(beanName, exposedObject, mbd);
- }
- }
在createBeanInstance中生成了Bean所包含的Java对象,这个对象的生成有很多不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,生成的方式由相关联的BeanDefinition来指定,进入createBeanInstance方法,有:
- return instantiateUsingFactoryMethod(beanName, mbd, args);
- return instantiateBean(beanName, mbd);
上面是其中的两个实例化方法,上面的是在BeanDefinition的FactoryMethod存在的情况下,使用工厂方法对bean进行实例化。下面一个是使用默认的构造函数对bean进行实例化。我们进入instantiateBean(beanName,mbd),可以看到有:
- return getInstantiationStrategy().instantiate(mbd, beanName, parent);
因为getInstantiationStrategy()返回的默认的实例化策略,而默认的实例化策略是CglibSubclassingInstantiationStrategy,也即用cglib来对bean进行实例化。CGLIB是一个常用的字节码生成器的类库,它提供了一系列的API来提供Java的字节码生成和转换功能。
我们再次回到doCreateBean()中的populateBean方法,看看在实例化Bean对象生成的基础上,spring怎样把这些bean对象的依赖关系设置好,完成整个依赖注入过程。在populateBean中,先是取得在BeanDefinition中设置的property值,这些property来自对BeanDefinition的解析,接着便开始进行依赖注入过程:
- //开始进行依赖注入过程,先处理autowire的注入
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
- //根据bean的名字进行autowire过程
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs);
- }
- //根据类型type进行autowire的过程
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- autowireByType(beanName, mbd, bw, newPvs);
- }
- pvs = newPvs;
- }
最后在通过applyPropertyValues对属性进行注入:
- applyPropertyValues(beanName, mbd, bw, pvs);
接着我们到applyPropertyValues中去看具体的对属性进行解析然后注入的过程,在其中会调用BeanDefinitionValueResolver对BeanDefinition进行解析,
- BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
接着为解析值创建一个拷贝,拷贝的数据将会被注入到bean中,它会先对PropertyValue判断,如果其没有经过转换则会调用resolveValueIfNecessary进行解析,然后注入到property中。下面到BeanDefinitionValueResolver中去看一下解析过程的实现,在函数resolveValueIfNecessary中包含了所有对注入类型的处理,以RuntimeBeanReference(其是在对BeanDefinition进行解析时生成的数据对象)为例:
- if (value instanceof RuntimeBeanReference) {
- RuntimeBeanReference ref = (RuntimeBeanReference) value;
- return resolveReference(argName, ref);
- }
- //当注入类型为RuntimeBeanReference时,进入resolveReference(…):
- private Object resolveReference(Object argName, RuntimeBeanReference ref) {
- try {
- //从RuntimeBeanReference取得reference的名字
- String refName = ref.getBeanName();
- refName = String.valueOf(evaluate(refName));
- //如果ref是在双亲的IOC容器中,那就到双亲IOC容器中去取
- if (ref.isToParent()) {
- if (this.beanFactory.getParentBeanFactory() == null) {
- //抛出异常BeanCreationException
- ……
- }
- return this.beanFactory.getParentBeanFactory().
- getBean(refName);
- }
- else {
- //在当前IOC容器中去取bean
- Object bean = this.beanFactory.getBean(refName);
- this.beanFactory.registerDependentBean(refName, this.beanName);
- return bean;
- }
- }
在上面的实现中,无论是到双亲的IOC容器中去取,还是在当前IOC容器中取,都会触发一个getBean的过程,这就触发了相应的依赖注入的发生。
这就完成了resolve的过程,为依赖注入准备好了条件。但真正的把Bean对象设置到它所依赖的另一个Bean的属性中去的地方是在BeanWrapper的setPropertyValues中(在分析populateBean的时候有提到),其中处理的属性是各种各样的。setPropertyValues的具体实现是在BeanWrapper的子类BeanWrapperImpl中:
在doCreateBean中执行完populateBean,完成Bean的生成和依赖注入以后,开始对Bean进行初始化,这个初始化过程包含了对后置处理器的postProcessBeforeInitializtion回调,具体实现在initializeBean方法中:
- Object wrappedBean = bean;
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
- }
- try {
- invokeInitMethods(beanName, wrappedBean, mbd);
- }
- catch (Throwable ex) {
- //抛出异常BeanCreationException
- }
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
- }
- return wrappedBean;
spring IOC源码分析(3)的更多相关文章
- Spring IOC 源码分析
Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...
- spring IoC源码分析 (3)Resource解析
引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- Spring Ioc源码分析系列--Ioc的基础知识准备
Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...
- Spring Ioc源码分析系列--前言
Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析
Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...
- Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理
Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...
- Spring Ioc源码分析系列--Bean实例化过程(一)
Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...
- Spring Ioc源码分析系列--Bean实例化过程(二)
Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...
随机推荐
- 汽车OBD2诊断程序开发 (原文转载,思路很清晰!)
1.因TL718已经为你建立了物理层.数据链层和部分应用层的协议,所以只要OBD2标准应用层协议文本,ISO15031-5 或 SAE J1979(这两个协议是相同的内容). 2.TL718诊断 ...
- MySQL常用查询
显示所有数据库 show datebases; 删除数据库 drop datebase dbName 创建数据库 create datebase [if not exists] dbName; //中 ...
- spark stream初探
spark带了一个NetworkWordCount测试程序,用以统计来自某TCP连接的单词输入: /usr/local/spark/bin/run-example streaming.NetworkW ...
- java反射温习一下
public class LoveReflect { public static class Demo implements Serializable{ } public static void ma ...
- WCF图片上传
WCF越来越流行,俺也在用,这是废话.项目中遇到需要图片上传,但是wcf上传会遇到一些异常,调试了N久,找了好多个解决方案才最终解决.代码直接贴上了 /// <summary> /// 笔 ...
- Microsoft SQL Server Product Samples:Database
从SQL Server 2005 之后示例数据都为AdventureWorks,需要的通过codeplex网站下载.这样设计的目的应该在于是生产库行不必要的用户以及权限分配. 从以下网址访问http: ...
- .Net 组件技术概述
1. 基本原理 组件是组件系统中功能的表现,没有组件就没有功能.特定接口是用于给组件管理程序来操纵.管理该组件,特定功能是组件需要完成的任务.在一个使用组件建立的产品中会随着功能数目的多少而会有多个组 ...
- 第一篇、HTML标签
<!--根标签--> <html> <head> <!--设置编码方式--> <meta charset="UTF-8"> ...
- 使用info.plist(或工程名-info.plist)向程序中添加软件Build ID或者版本号信息
在实际应用程序开发过程中,经常需要向程序中添加软件版本号或者类似的信息,以保证之后发现问题时知道bug所在的版本,我们可以通过在工程名-info.plist文件中设置相关的key/value对(键/值 ...
- Mysql 的变量
变量 MySQL是一门编程语言.所以存在变量.流程控制.函数.存储过程.触发器 MySQL分系统变量,与自定义变量 MySQL的某些功能是通过系统变量来实现的.例如:autocommit 查看系统变量 ...