April 20, 2018

spring IOC原理之:创建实例

上一章我们讲完了BeanDefinition,接下我们继续来讲创建实例。

1. BeanDefinition创建好了一脸懵逼?

不用懵逼,获取到完整的RootBeanDefintion后,就可以拿这份定义信息来实例化Bean。

2. 如何实例化Bean?

首先我们编写一个Service类:

从main方法出发:

进入SpringApplication#run方法:

进入org.springframework.context.support.AbstractApplicationContext#refresh方法,refresh方法负责实例化所有的bean:

进入org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons方法:

这里通过遍历beanNames列表逐个实例化bean,通过断点可以看到等待实例化的bean:

接着通过getBean方法创建实例:

进入org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法:

在doGetBean方法中,首先会尝试从三级缓存获取bean实例(这是为了解决循环依赖,关于循环依赖将在下一章节展开):

因为Demo1Service是初次实例化,因此该方法返回null。

进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法来进行创建:

进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法:

调用createBeanInstance方法后,bean已经实例化,但并未完成依赖注入,接下来会通过populateBean方法完成相关依赖bean注入:

3. createBeanInstance方法具体如何new bean?

深入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance方法:

有三种实例化方式,分别是:

1. 使用工厂方法创建实例

2. 使用有参构造函数创建实例

3. 使用无参构造函数创建实例

断点进入AbstractAutowireCapableBeanFactory#createBeanInstance方法,可以看到demoService2的实例是通过无参构造函数创建的。:

具体来说,spring使用实例化策略类SimpleInstantiationStrategy#instantiate方法来创建实例:

然后使用BeanUtils#instantiateClass方法来创建实例:

最后使用反射,调用构造函数ctor.newInstance(args),创建demoService2实例。

4. 现在我们已经创建了demoService2实例,但是它依赖的demoService实例是怎么注入的呢?

答案是通过AbstractAutowireCapableBeanFactory#populateBean方法:

该方法会获取当前BeanFactory的所有InstantiationAwareBeanPostProcessor,然后逐个遍历调用postProcessPropertyValues方法:

可以看到总共有19个BeanPostProcessor,其中

CommonAnnotationBeanPostProcessor负责注入@Resource注解的bean

AutowiredAnnotationBeanPostProcessor负责注入@Autowired注解的bean。

CommonAnnotationBeanPostProcessor#postProcessPropertyValues

该方法调用了InjectionMetadata#inject方法,注入依赖的demoService实例:

然后使用InjectionMetadata类的内部类InjectedElement#inject方法:

最后通过反射将demoService实例填充到属性private DemoService demoService上去:

demoService实例是getResourceToInject方法返回的,该方法有3个重写方法:

demoService作为被@Resource注解注入的bean,自然是使用ResourceElement#getResourceToInject方法获取的:

在该方法处断点,可以看到从resourceFactory中获取到了demoService的实例,resourceFactory是DefaultListableBeanFactory的实例,也就是IOC容器,requestingBeanName是要求注入的实例demoService2。

5. InjectionMetadata是如何封装的?

我们回到CommonAnnotationBeanPostProcessor#postProcessPropertyValues方法,可以看到InjectionMetadata是通过CommonAnnotationBeanPostProcessor#buildResourceMetadata方法构建的:

InjectionMetadata类有2个主要属性,targetClass(要被安排注入bean的目标类)和injectedElements(即将被注入的bean列表):