以前在网上看过一些关于spring 自动装配的文章,有人说@Autowired就是自动装配,其实这是不正确的,今天我将会以官网文档和源码来说明这个问题。

讲自动装配之前我想先看一下​​官方文档​​对自动装配的描述,可以看到,自动装配有四种模式:

Spring @Autowired 自动装配 ?_自动装配

从上图可以看到,默认Mode为no,代表没有自动装配,然后我们再看看AutowireCapableBeanFactory中定义的几个常量,其实就是跟上图中四种模式对应的,但是下图中有5个,只不过第5个AUTOWIRE_AUTODETECT已经被废弃了,所以我们认为只有四种模式即可。

Spring @Autowired 自动装配 ?_xml配置_02

接着,可以从源码着手讲@Autowired为什么不是自动装配了,上图:

Spring @Autowired 自动装配 ?_xml配置_03

从上图中可以看到,A依赖了B,然后在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean中断点,并加上条件beanName.equals(“a”),所以只有beanName为a时,才会进入这个断点,断点往下执行后可以看到resolvedAutowireMode=0及beanDefinition中的autowireMode=0,结合上文中提到的四种装配模式和对应的数值,可以发现a的自动装配模式为no,也就是默认没有自动装配,这就是最直接的证据说明@Autowired不是自动装配。

但是,最后控制台打印出b的地址值,说明注入b成功,那么是怎么注入的呢,接着上一幅图,拿到resolvedAutowireMode的值后继续往下执行,如下图:

Spring @Autowired 自动装配 ?_spring_04

从上图中可以看到,spring调用了bean的后置处理器来完成属性注入,默认有6个,最开始bw中的wrappedObject中的b=null,直到beanPostProcessor=AutowiredAnnotationBeanPostProcessor且执行完 if 逻辑,可以看到b已经有值了,这时候已经完成了对属性b的注入,最后直接执行完所有流程,控制台打印出b的地址。

a完成属性b的注入实际上是通过 field.set 方式注入的,具体代码可见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

Spring @Autowired 自动装配 ?_自动装配_05

其实,从int resolvedAutowireMode = mbd.getResolvedAutowireMode(); 到调用bean的后置处理器中间还有一段逻辑,如下图:

Spring @Autowired 自动装配 ?_xml配置_06

这段逻辑对应的就是:当自动装配模式为BY_NAME或BY_TYPE时的属性注入,既然加了@Autowired不是自动装配,那么怎么模拟自动装配呢?如下图:

Spring @Autowired 自动装配 ?_自动装配_07

从上图可以看出,A中已经没有属性b,只有setB方法,然后自定义了一个MyBeanFactoryPostProcessor来修改a的自动装配模式为2-byType,在执行org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean的断点resolvedAutowireMode后,resolvedAutowireMode=2,然后进入了if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) 的逻辑,直接执行完,发现控制台打印出b的地址,说明注入成功,这时候a中已经没有属性b,更不要提@Autowired 了,这说明自动装配其实与@Autowired 无关。

实现自动装配还有另一种方式,就是xml配置,这时候已经不需要MyBeanFactoryPostProcessor了,简单演示一下,如下图:

Spring @Autowired 自动装配 ?_xml配置_08

从上图可以看出,通过xml配置方式和java配置方式实现的最终效果一致,通过xml配置方式也可以看出,只需要设置autowire = “byType” 就完成自动装配了(当然还有byName和constructor),并不需要像下图一样配置:

Spring @Autowired 自动装配 ?_xml配置_09

其实,从官网所讲的自动装配的优点中也可以看出,上图示例属于手动装配,如图:

Spring @Autowired 自动装配 ?_自动装配_10

简言之,假设A中现在新增依赖项C,那么就不需要再去xml中指定C的依赖关系,可以自动满足和注入。

参考文档: https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/core.html#beans-factory-autowire