springboot是如何实现自动装配的(一)注解分析

系列文章目录

springboot是如何实现自动装配的(一)注解分析
springboot是如何实现自动装配的(二)条件装配
springboot是如何实现自动装配的(三)静态资源配置源码



前言

本章深入源码来分析springboot自动装配的原理。来看看神奇的自动装配是怎么一回事。

一、从何处入手

我们从启动类的注解入手,先看启动类。
@SpringBootApplication
public class SourceAnalysisApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(SourceAnalysisApplication.class, args);
    }

}

启动类上只有一个注解,这是一个合成注解,我们来看一下里面都包含了什么。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    
     @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    
    

这么多注解抛去上面的四个元注解 @Target @Retention @Documented @Inherited 还剩三个,其中@SpringBootConfiguration点开源码我们看的出来他就是一个配置类
在这里插入图片描述
@ComponentScan 是一个包扫描规则,显然也不是我们要找的
那么就剩下一个了,就是==@EnableAutoConfiguration==

@EnableAutoConfiguration

@EnableAutoConfiguration通过名字我们就知道,它是开启自动配置。那么它究竟干了什么呢?我们进去看一看。
在这里插入图片描述
去掉上面的元注解。实际上就是两个注解

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    
    

@AutoConfigurationPackage

我们来看看@AutoConfigurationPackage里面是个啥东西

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
    
    

同样去掉元注解,它就是个@Import,@Import注解的作用就是给容器中导入一个组件,导入哪个组件呢,就是括号里面的AutoConfigurationPackages.Registrar.class类,那这个类是干什么用的呢,我们进去看一下。
在这里插入图片描述
首先它是一个内部类,主要就是调用了一个方法进行批量导入组件。
这个方法有两个参数,第一参数代表注解元信息。
由于我们是通过@AutoConfigurationPackage注解导入的这个类。这个注解又是@EnableAutoConfiguration里的合成注解而@EnableAutoConfiguration又是@SpringBootApplication注解里的合成注解。最后SpringBootApplication注解标在了我们的启动类上。
说了这么多废话其实就是启动类的元信息。我们来看DEBUG信息
在这里插入图片描述
然后这货又干了些啥呢。它new了一个PackageImports类,按照名字来看是包要导入的东西。
在这里插入图片描述
整个就相当于把我们的元注解信息注入进去,然后获取包名(.getPackageName方法),那获取到的是什么?就必然是我们启动类的包名啊!验证一下,选择这行代码,右键选择
在这里插入图片描述
在这里插入图片描述
查看结果,与预期的一致。
在这里插入图片描述

然后转换成一个数组,最后注册进来。
在这里插入图片描述

总结一下@AutoConfigurationPackage这个注解就是把某个包下面的所有组件注册进来。

@Import(AutoConfigurationImportSelector.class)

接下来分析@EnableAutoConfiguration的第二个注解,同样第二个注解也是导入一个类AutoConfigurationImportSelector.class。我们来看这个类
在这里插入图片描述
我们看到这个方法实际上是调用getAutoConfigurationEntry()这个方法得到所有配置,然后得到配置数组返回出去的。那么我们先搞清楚getAutoConfigurationEntry()这个方法是干什么的。

getAutoConfigurationEntry

在这里插入图片描述
我们DEBUG这个方法,发现他调用了getCandidateConfigurations方法,即获取候选配置。然后发现获取了多少呢?127个。
在这里插入图片描述
也就是说这127个组件默认要导入到容器中。
好继续,我们来看getCandidateConfigurations又是怎么获取候选配置的呢,继续打断点调试。
在这里插入图片描述

我们进入getCandidateConfigurations方法内部,
在这里插入图片描述在这里插入图片描述

我们发现它调用了Spring的工厂加载器,利用工厂进行加载。
我们再继续进入。
在这里插入图片描述
发现是用loadSpringFactories得到所有的组件

那么loadSpringFactories又是怎么工作的呢,继续打断点。
在这里插入图片描述
在这里插入图片描述
如上图一开始我们就走到了classLoader.getResources这个方法来加载资源文件,参数的常量值为"META-INF/spring.factories",就是说从这个位置加载一个文件。就是默认扫描当前系统里面所有这个位置的文件。
我们来看看我们引入的包里面有没有这个文件。
在这里插入图片描述
当然是有的有,有的没有。我们直接看最核心的包,就是上图第二个包

spring-boot-autoconfigure-2.3.0.RELEASE.jar
这个包名一看便知道,是自动配置。看看它的spring.factories文件里面是什么

在这里插入图片描述

我们发现Auto Configure注释下面的写了好多 XXXAutoConfiguration。总共数量是127个,这回知道了,原来上面说的加载的127个配置,是在这里写死的。

总结

@AutoConfigurationPackage注解

1.给容器中导入一个组件@Import(AutoConfigurationPackages.Registrar.class)
2.利用Registrar类的registerBeanDefinitions方法给容器注册一系列组件。
将指定包路径下的所有组件注册进来,即启动类包路径。

@Import(AutoConfigurationImportSelector.class)注解

1.利用 protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)给容器中批量导入一些组件。
2.调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取所有需要导入到容器的配置。
3.利用工厂加载器private static Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader) 得到所有的组件。
4.从META-INF/spring.factories位置来加载一个文件。
spring-boot-autoconfigure-2.3.0.RELEASE.jar这个包下的META-INF/spring.factories文件中配有写死的127个默认加载的自动配置。

但是,并不是所有自动的这些配置文件对应的组件都要装配到容器中,下一篇我们来继续分析一下springboot是如何按需装配的。

猜你喜欢

转载自blog.csdn.net/qq_31277409/article/details/114729521