先从启动配置注解 SpringbootApplication来看,点开查看。
最上面的四个是元注解。
主要是下面的三个注解。

spring boot2 版本_java

第一个:@SpringBootConfiguration, 点进去查看,

spring boot2 版本_spring_02


可以看到,主要是一个Configuration 注解,标识这个类是配置类。

第三个(第二个在下面看):@ComponentScan

指定组件扫描的路径,指定扫描哪些组件。

第二个是核心 ,@EnableAutoConfiguration

点击进入查看也有两个核心注解:

spring boot2 版本_spring_03


1,第一个:@AutoConfigurationPackage, 点进去查看。有一个@Import注解导入了一个Registter。

spring boot2 版本_spring boot_04


这里实际上使用Register 导入了一堆组件,并不是只导入了这一个组件,进入Register,

会调用这里的方法。

spring boot2 版本_数组_05

至于为什么这个可以看Import 注解的作用,高级用法。

spring boot2 版本_spring boot2 版本_06

这里第一个方法的参数是一个注解的元信息, 这个注解是谁?我们从AutoConfigurationPackage跳过来的,这个注解就是这个。 而注解的元信息表示注解标在了哪个类上,其属性值是什么。

在该方法上加个断点debug:

spring boot2 版本_spring boot_07


这个注解标注的类在启动类MainApplication上,因为@SpringBootApplication是一个合成注解,包含这个AutoConfigurationPackage。所以从debug信息中可以看到MainApplication,如下:

spring boot2 版本_数组_08


然后这个方法干了啥呢?

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
 AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages
 			.PackageImports(metadata))
            .getPackageNames()
            .toArray(new String[0]));
        }

先new 了一个对象,拿到元信息metadata,然后获取的报名,即这一段代码:new AutoConfigurationPackages

.PackageImports(metadata))

.getPackageNames()

这一段拿到了启动类所在的包路径:如下:

spring boot2 版本_spring_09


最后一个.toArray(new String[0])); 将所有该包下组件都放入到一个数组中了(这里就不要理解为转成一个数组了,放到一个数组最好了)。

然后通过AutoConfigurationPackages.register,注册进去。

这就解释了为什么用Springboot时,默认的包路径?是启动类所在的包。。。2,然后看@EnableAutoConfiguration 的第二个注解了@Import({AutoConfigurationImportSelector.class}) ,这个使用了AutoConfigurationImportSelector 类。进入这个类里面查看

spring boot2 版本_spring boot2 版本_10


这个selectImports 指定要导入哪些,都放到String数组返回,根据这个数组来确定。

所以核心都落在了this.getAutoConfigurationEntry 这个方法上了。

跳到这个方法,打一个断点debug:

spring boot2 版本_spring boot2 版本_11

拿到configurations 大小有127个。这是拿到127个组件,这些是默认导入到容器中的组件。

单步进入:进入这个方法查看:使用的SpringFactoriesLoader 加载

spring boot2 版本_spring boot_12


在进入这个loadFactoryNames 方法

spring boot2 版本_spring boot_13

再进入这个loadSpringFactories方法:最后返回的是一个map list集合。

spring boot2 版本_java_14

初始时上面方法的result 必定是空的,所以会优先执行else 的语句块

spring boot2 版本_spring boot2 版本_15


这里会加载当前工程下所有包,包括导入的包MET-INF 下的spring.factories。

spring boot2 版本_spring boot2 版本_16


有些jar包就没有这个spring.factories

spring boot2 版本_java_17


但是springboot的包下就存在这个springboot.factories

spring boot2 版本_spring_18


但是前面的127个组件,实际上是autoconfigration 包下的spring.factories所指定的自动配置类。

spring boot2 版本_spring boot2 版本_19


但是这127个没有全部放入到springboot的容器中,有些是生效的有些是没有生效的。这127个默认场景的是

** 默认全部加载,但是最终会按需配置。 **

这些配置是根据标在它上面的@Conditional相关注解判断是否生效。

例如:下面的aop 配置,只有Advice 类存在这个配置类才会生效。

spring boot2 版本_spring boot2 版本_20


其他的autoconfigure类也相同。

总结:

@SpringBootConfiguration :指定了当前类是一个配置类 。
 @ComponentScan : 指定扫描的包路径。
 @EnableAutoConfiguration 的@AutoConfigurationPackage 确定了启动类所在的包。
 @EnableAutoConfiguration 的@Import({AutoConfigurationImportSelector.class}) :确定了要加载的所有场景的自动配置类,并根据application.properties文件按需进行配置。