1.IOC容器的依赖注入

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

在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中:

  1. public Object getBean(String name) throws BeansException {
  2. return doGetBean(name, null, null, false);
  3. }

可以看到具体的注入过程转移到doGetBean(String…)中,在这个方法中,它首先从缓存中取,如果单件模式的bean已经被创建,则这种bean请求不需要重复的创建,调用

  1. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

跟踪进入getObjectForBeanInstance(…,null),可以知道因为最后的RootBeanDefinition参数是null,所以执行的是:

  1. if (mbd == null) {
  2. object = getCachedObjectForFactoryBean(beanName);
  3. }

而getCachedObjectForFactoryBean(beanName)中实现,其实现很简单,就是在缓存的bean map中查找bean返回。

继续回到doGetBean(String…)方法中:

  1. //取当前bean的所有依赖bean,这样就会触发getBean的递归调用,直至取到一个没有任何依赖的bean为止
  2. String[] dependsOn = mbd.getDependsOn();
  3. if (dependsOn != null) {
  4. for (String dependsOnBean : dependsOn) {
  5. getBean(dependsOnBean);
  6. //注册依赖的bean实例,具体实现过程在DefaultSingletonBeanRegistry中实现,其实就是将依赖的bean添加到依赖的hashmap中
  7. registerDependentBean(dependsOnBean, beanName);
  8. }
  9. }
  10. //通过调用createBean来,创建单例bean的实例
  11. if (mbd.isSingleton()) {
  12. sharedInstance = getSingleton(beanName, new ObjectFactory() {
  13. public Object getObject() throws BeansException {
  14. try {
  15. return createBean(beanName, mbd, args);
  16. }
  17. catch (BeansException ex) {
  18. destroySingleton(beanName);
  19. throw ex;
  20. }
  21. }
  22. });
  23. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  24. }
  25. //同样调用createBean创建prototype的bean实例
  26. else if (mbd.isPrototype()) {
  27. // It's a prototype -> create a new instance.
  28. Object prototypeInstance = null;
  29. try {
  30. beforePrototypeCreation(beanName);
  31. prototypeInstance = createBean(beanName, mbd, args);
  32. }
  33. finally {
  34. afterPrototypeCreation(beanName);
  35. }
  36. bean=getObjectForBeanInstance(prototypeInstance,name, beanName, mbd);
  37. }

继续看createBean(…),可以看到在AbstractBeanFactory中它只是个抽象类,具体的实现交给其子类(又见模板模式),进入子类AbstractAutowireCapableBeanFactory中看createBean的具体实现:

  1. Object beanInstance = doCreateBean(beanName, mbd, args);

其具体的实现转到doCreateBean(String…),这里我们看到与依赖注入关系比较密切的方法有createBeanInstance和populateBean。

  1. BeanWrapper instanceWrapper = null;
  2. if (mbd.isSingleton()) {
  3. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  4. }
  5. if (instanceWrapper == null) {
  6. instanceWrapper = createBeanInstance(beanName, mbd, args);
  7. }
  1. // Initialize the bean instance.
  2. Object exposedObject = bean;
  3. try {
  4. populateBean(beanName, mbd, instanceWrapper);
  5. if (exposedObject != null) {
  6. exposedObject = initializeBean(beanName, exposedObject, mbd);
  7. }
  8. }

在createBeanInstance中生成了Bean所包含的Java对象,这个对象的生成有很多不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,生成的方式由相关联的BeanDefinition来指定,进入createBeanInstance方法,有:

  1. return instantiateUsingFactoryMethod(beanName, mbd, args);
  1. return instantiateBean(beanName, mbd);

上面是其中的两个实例化方法,上面的是在BeanDefinition的FactoryMethod存在的情况下,使用工厂方法对bean进行实例化。下面一个是使用默认的构造函数对bean进行实例化。我们进入instantiateBean(beanName,mbd),可以看到有:

  1. return getInstantiationStrategy().instantiate(mbd, beanName, parent);

因为getInstantiationStrategy()返回的默认的实例化策略,而默认的实例化策略是CglibSubclassingInstantiationStrategy,也即用cglib来对bean进行实例化。CGLIB是一个常用的字节码生成器的类库,它提供了一系列的API来提供Java的字节码生成和转换功能。

我们再次回到doCreateBean()中的populateBean方法,看看在实例化Bean对象生成的基础上,spring怎样把这些bean对象的依赖关系设置好,完成整个依赖注入过程。在populateBean中,先是取得在BeanDefinition中设置的property值,这些property来自对BeanDefinition的解析,接着便开始进行依赖注入过程:

  1. //开始进行依赖注入过程,先处理autowire的注入
  2. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  3. MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
  4. //根据bean的名字进行autowire过程
  5. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
  6. autowireByName(beanName, mbd, bw, newPvs);
  7. }
  8. //根据类型type进行autowire的过程
  9. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  10. autowireByType(beanName, mbd, bw, newPvs);
  11. }
  12. pvs = newPvs;
  13. }

最后在通过applyPropertyValues对属性进行注入:

  1. applyPropertyValues(beanName, mbd, bw, pvs);

接着我们到applyPropertyValues中去看具体的对属性进行解析然后注入的过程,在其中会调用BeanDefinitionValueResolver对BeanDefinition进行解析,

  1. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

接着为解析值创建一个拷贝,拷贝的数据将会被注入到bean中,它会先对PropertyValue判断,如果其没有经过转换则会调用resolveValueIfNecessary进行解析,然后注入到property中。下面到BeanDefinitionValueResolver中去看一下解析过程的实现,在函数resolveValueIfNecessary中包含了所有对注入类型的处理,以RuntimeBeanReference(其是在对BeanDefinition进行解析时生成的数据对象)为例:

  1. if (value instanceof RuntimeBeanReference) {
  2. RuntimeBeanReference ref = (RuntimeBeanReference) value;
  3. return resolveReference(argName, ref);
  4. }
  5. //当注入类型为RuntimeBeanReference时,进入resolveReference(…):
  6. private Object resolveReference(Object argName, RuntimeBeanReference ref) {
  7. try {
  8. //从RuntimeBeanReference取得reference的名字
  9. String refName = ref.getBeanName();
  10. refName = String.valueOf(evaluate(refName));
  11. //如果ref是在双亲的IOC容器中,那就到双亲IOC容器中去取
  12. if (ref.isToParent()) {
  13. if (this.beanFactory.getParentBeanFactory() == null) {
  14. //抛出异常BeanCreationException
  15. ……
  16. }
  17. return this.beanFactory.getParentBeanFactory().
  18. getBean(refName);
  19. }
  20. else {
  21. //在当前IOC容器中去取bean
  22. Object bean = this.beanFactory.getBean(refName);
  23. this.beanFactory.registerDependentBean(refName, this.beanName);
  24. return bean;
  25. }
  26. }

在上面的实现中,无论是到双亲的IOC容器中去取,还是在当前IOC容器中取,都会触发一个getBean的过程,这就触发了相应的依赖注入的发生。

这就完成了resolve的过程,为依赖注入准备好了条件。但真正的把Bean对象设置到它所依赖的另一个Bean的属性中去的地方是在BeanWrapper的setPropertyValues中(在分析populateBean的时候有提到),其中处理的属性是各种各样的。setPropertyValues的具体实现是在BeanWrapper的子类BeanWrapperImpl中:

在doCreateBean中执行完populateBean,完成Bean的生成和依赖注入以后,开始对Bean进行初始化,这个初始化过程包含了对后置处理器的postProcessBeforeInitializtion回调,具体实现在initializeBean方法中:

  1. Object wrappedBean = bean;
  2. if (mbd == null || !mbd.isSynthetic()) {
  3. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  4. }
  5. try {
  6. invokeInitMethods(beanName, wrappedBean, mbd);
  7. }
  8. catch (Throwable ex) {
  9. //抛出异常BeanCreationException
  10. }
  11. if (mbd == null || !mbd.isSynthetic()) {
  12. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  13. }
  14. return wrappedBean;

spring IOC源码分析(3)的更多相关文章

  1. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  2. spring IoC源码分析 (3)Resource解析

    引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource  ...

  3. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  4. Spring Ioc源码分析系列--Ioc的基础知识准备

    Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...

  5. Spring Ioc源码分析系列--前言

    Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...

  6. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  7. Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析

    Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...

  8. Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理

    Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...

  9. Spring Ioc源码分析系列--Bean实例化过程(一)

    Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...

  10. Spring Ioc源码分析系列--Bean实例化过程(二)

    Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...

随机推荐

  1. vb.net写的odbc连接dsn数据源和ole链接oracle的小例子

    最近由于工作需要开始接触vb2010,也叫vb.net.相比vb6.0有面向对象编程的优势.同时接触一门新语言,要更快的实际应用起来,链接数据库是必不可少的.之前用vba写过一个售书工具,正好可以拿来 ...

  2. jqgrid 的编辑信息提示

    在编辑时,无外乎两种结果:成功和失败.在form edit的弹出编辑窗体中隐藏了两个单元(td),一个的ID是FormError,另一个没有id,有class叫做topinfo.就是这两个家伙可以分别 ...

  3. (转)fastdfs group通过添加硬盘扩容

    通过给group的机器添加硬盘的方式,实现某个group的扩容. fastdfs在一台服务器支持多个store_path,每个store_path指向一个存储路径.url “M00/3F/E1/oYY ...

  4. js事件(Event)知识整理[转]

    事件注册 平常我们绑定事件的时候用dom.onxxxx=function(){}的形式 这种方式是给元素的onxxxx属性赋值,只能绑定有一个处理句柄. 但很多时候我们需要绑定多个处理句柄到一个事件上 ...

  5. UVA 11021 - Tribles(概率)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=481&page=s ...

  6. 关于HTML5标签不兼容(IE6~8)

    HTML5的语义化标签以及属性,可以让开发者非常方便地实现清晰的web页面布局,加上CSS3的效果渲染,快速建立丰富灵活的web页面显得非常简单. 比较常用的HTML5的新标签元素有: <hea ...

  7. JavaScript 零散知识点1 (正则表达式+定时器+hover)

    1.clear:both清楚浮动影响//css中 2.正则表达式 search方法 :指明是否存在相应的匹配,如找到一个返回一个整数值,表明这个匹配距离字符串开始的偏移位置,如果没有找到匹配返回-1f ...

  8. JAXB - The Object Factory

    Usually hidden in the middle of the list of the classes derived from the types defined in an XML sch ...

  9. sqlserver 2012 重启是 ID 自动增长 1000的问题

    1. Open "SQL Server Configuration Manager"2. Click "SQL Server Services" on the ...

  10. 解决IllegalStateException: Can not perform this action after onSaveInstanceState:

    今天做项目中的支付宝功能,是在fragment中做的,在支付成功后,想切换到支付成功的页面. 结果就报错了IllegalStateException: Can not perform this act ...