@TOC

前言

前面我们分析了 IoC 之 BeanDefinition 的扫描注册,那么接下来要解决的问题就是依赖关系的注入。

通过 IoC之BeanDefinition扫描注册 的分析,我们知道 BeanDefinition 注册阶段,bean 的实例是没有产生的,
它只是将 BeanDefinition 注册到了 BeanDefinitionRegistry 中。

那么 bean 依赖的属性又是在什么时候注入到 bean 的实例中的呢?

版本约定

Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

前面分析 BeanDefinition注册 时,我们知道依赖的注入是通过 InjectionMetadata.InjectedElement#inject() 来完成的。那么,我们就以这个点做为突破口。
AutowiredFieldElement 是来处理 @Autowired 属性类型注入的,所以,我们将断点打在 AutowiredFieldElement#inject() 上。
AutowiredFieldElement

更多 InjectedElement 的知识请移步 @Resource与@Autowired的区别

我们可以看到,依赖的注入发生在 AbstractApplicationContext#finishBeanFactoryInitialization() 阶段,进行 populateBean 的时候。

查看 DefaultListableBeanFactory#preInstantiateSingletons() 的源码可以发现,Spring 会去循环所有的 beanDefinitionNames,逐个调用 getBean() 来初始化 bean。

// DefaultListableBeanFactory#preInstantiateSingletons()
public void preInstantiateSingletons() throws BeansException {
    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(
                                (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    } else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            } else {
                getBean(beanName);
            }
        }
    }
......
}

从调用堆栈中,我们可以看到 inject() 之前做了两个重要的动作:doCreateBean() 和 populateBean()

doCreateBean(): 创建 bean 的实例
populateBean(): 填充 bean 依赖的属性

所以,依赖的注入是发生在创建 bean 的实例后,为 bean 的实例填充属性的时候(populateBean)。

AutowiredFieldElement#inject() 的代码比较简单,最关键的代码就是从 beanFactory 中将依赖解析出来:

Object value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

resolveDependency2

解析依赖的详细逻辑----doResolveDependency

解析依赖的详细逻辑在 DefaultListableBeanFactory#doResolveDependency() 中:
doResolveDependency

DependencyDescriptor#resolveCandidate() 方法会触发依赖 bean 的加载动作,里面会调用 BeanFactory#getBean(),从而触发依赖 bean 的加载流程。

// DependencyDescriptor#resolveCandidate()
public Object resolveCandidate(String beanName, Class&lt;?&gt; requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}

依赖解析时的逻辑和顺序如下:

  1. 是否是 @Value 类型的依赖
  2. 是否是 Collection、Array、Map 等容器对象的依赖
  3. 是否是 resolvableDependency 类型的依赖
  4. 以上都不是,就会走普通依赖的注入流程 --> DependencyDescriptor#resolveCandidate()

普通依赖的注入流程也就是 getBean() 的流程

可以看出,Spring 能处理的依赖类型有多种

  1. @Value 类型的依赖
  2. Collection、Array、Map 等容器对象的依赖
  3. resolvableDependency 类型的依赖
  4. 普通 bean 的依赖

@Value 也是做为一种依赖类型在处理的。
也就是说: bean 里面被 @Value、@Component、@Autowired、@Resource 标记的属性都会被当作依赖进行注入。
划重点:依赖注入的过程,可以认为是 bean 中属性填充的过程。

总结

Spring 对依赖的注入 AbstractApplicationContext#finishBeanFactoryInitialization 阶段。
这个时候,会遍历所有的 beanDefinitionNames,为每一个 BeanDefinition 去创建实例。
创建 BeanDefinition 的实例时,会先实例化 bean,然后再为 bean 的实例填充属性(populateBean),填充属性的过程也就是依赖注入的过程。
具体的注入动作是由 InjectionMetadata.InjectedElement#inject() 来完成的。

依赖解析时的逻辑和顺序如下:

  1. 是否是 @Value 类型的依赖
  2. 是否是 Collection、Array、Map 等容器对象的依赖
  3. 是否是 resolvableDependency 类型的依赖
  4. 以上都不是,就会走普通依赖的注入流程 --> DependencyDescriptor#resolveCandidate()

如果本文对你有所帮助,欢迎点赞收藏
有关 Spring 源码方面的问题欢迎留言一起交流...

公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…

阅读更多文章,请关注公众号: 老王学源码
gzh_b2.png


博主好课推荐:

课程 地址
Dubbo源码解读——通向高手之路 https://edu.51cto.com/sd/2e565
正则表达式基础与提升 https://edu.51cto.com/sd/59587