2.4 IoC容器的依赖注入

依赖注入的过程是用户第一次向IoC容器索要Bean时触发的,也就是getBean方法。(例外:通过控制lazy-init属性来让容器完成对Bean的预实例化,这个预实例化实际上就是一个依赖注入,但是在初始化的时候完成)

依赖注入可以分为两个过程:一是bean所包含的Java对象的创建,二是对bean对象的初始化。

查看BeanFactory的getBean的实现方法,有三个类实现了该方法:SimpleJndiBeanFactory,StaticListableBeanFactory和AbstractApplicationContext。我们比较熟悉的是AbstractApplicationContext这个类,以这个类来看下依赖注入的过程,大致如下图所示:

上图的一个简要过程说明:

AbstractApplicationContext类的getBean方法中,真正实现向IoC容器索取被管理的Bean的功能的是getBeanFactory().getBean方法。继续追踪getBeanFactory()方法,看到返回的对象是DefaultListableBeanFactory容器对象,DefaultListableBeanFactory容器的父类AbstractBeanFactory中实现了getBean方法。所以,继续看AbstractBeanFactory的getBean方法,在这个方法中,有几个地方要注意:

  • 对于单例模式的bean的创建:只创建一次,所以会先检查再创建;
  • BeanFactory是对象工厂,里面存的是bean的对象,可以从这里面取bean对象,FactoryBean是一个Bean,只不过这个bean有生产对象能力的工厂bean;
  • 注意getBean里面的递归调用,也就是直到找到一个没有依赖的bean创建出来,再依次把前面的bean创建。

上面所述过程只是定义了不同类型的bean采用不同的创建方式,归根到底还是没有创建bean,具体的创建bean的过程采用了委派模式,交由其实现类AbstractAutowireCapableBeanFactory完成。那么再看AbstractAutowireCapableBeanFactory里面的createBean方法中的doCreateBean方法,这里有两个关键的地方:

1. createBeanInstance:创建对象的方法。

在createBeanInstance()中,可以通过工厂方法或者自动装配进行实例化,用的最多的是无参构造器实例化。带参数构造器实例化也很常见,这需要具体的实例化策略,要看SimpleInstantiationStrategy类的instantiate方法。这个类是Spring用来生成Bean对象的默认类,它提供两种实例化Java对象的方法,一种是利用JVM反射机制的BeanUtils(通过无参构造器实例化),一种是通过CGLIB。createBeanInstance()中四种实例化的方式:

  • 工厂方法实例化
  • 自动装配实例化
  • 无参构造器实例化
  • CGLIB实例化(常用)

2. populateBean:完成属性注入。

在populateBean()中,applyPropertyValues()中代码的执行顺序:首先看属性是否已经是符合注入标准的类型,如果是就直接开始注入;否则,判断属性是否需要转换解析,需要的话则进行解析-->解析完成,开始注入。

解析过程在resolveValueIfNecessary()中进行。在这个方法中,根据不同的属性类型,分别进入了不同的方法:

(1)引用类型的解析(resolveReference()方法):如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象 ,从当前容器取,如果对象没有创建,则递归调用getBean。

(2)其他类型的解析:如list,递归解析list的每一个元素,又走了一遍resolveValueIfNecessary方法,也就是说如果list里面也是配置的ref,那么会调用到对引用类型解析。

完成以上解析过程后,已经为依赖注入准备好了条件,在applyPropertyValues方法中,可以看到BeanWrapper的setPropertyValues实现了真正的依赖注入。

猜你喜欢

转载自my.oschina.net/u/3342874/blog/1820156
今日推荐