废话不多话说,直接从 @SpringBootApplication注解开始。众所周知,被该注解标注的类为主程序类,标注这个类是一个SpringBoot的应用。而该注解又由三个另外的注解合成:@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan。
由于@SpringBootConfiguration和@ComponentScan的作用读者们应该了解不少,所以我们直接从@EnableAutoConfiguration注解开始。
我们进入@EnableAutoConfiguration,发现该注解由@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)组成,我们先进入@AutoConfigurationPackage。
- @AutoConfigurationPackage:自动配置包,注册主程序的根packages中的组件。
该注解通过@Import为我们注册了一个名为Registrar的组件。我们进入该类,看看它为我们做了什么。
该方法的AnnotationMetadata参数,传递了当前注解的元信息,由于该注解合成于@SpringBootApplication,所以该注解的元信息也即为我们标注了@SpringBootApplication的主程序类的元信息。
然后通过注解的元信息,获取我们的包名,为我们注册各种包下的组件。
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
获得的包名即为主程序所在的包。
所以,@AutoConfigurationPackage的作用为将某一个包下(主程序所在包及其子包)的所有组件注册到我们的容器中。 这也解释了,SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。
- @Import(AutoConfigurationImportSelector.class)
利用该方法给容器批量导入一些组件。
getAutoConfigurationEntry(annotationMetadata);
获取到所有需要导入到容器中的配置类。
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
调试该方法,发现该方法最终会我们导入131个组件。
通过工厂加载我们需要导入的组件。
可以看到加载的组件是从META-INF/spring.factories中加载进来的,即会扫描我们当前系统里面所有META-INF/spring.factories位置的文件。
spring-boot-autoconfigure-2.5.5.jar包下也存在META-INF/spring.factories,进入该文件,发现自动配置的131个组件在该文件中已被写死。所以SpringBoot一启动就会加载spring-boot-autoconfigure-2.5.5.jar/META-INF/spring.factories文件下的配置类,这也就是自动配置的原理。
但是,加载了所有的配置类,我们不一定都会用得到,所以要根据我们的需求配置。@Conditional注解为我们解决了该问题。我们查看AopAutoConfiguration,可以知道即使SpringBoot为我们自动加载了所有配置类,但是通过@Conditional限定某些类是否能产生作用,这也就是条件装配了。
总结:
- SpringBoot会自动加载所有配置类。
- 每个自动配置类根据条件决定是否生效。默认都会绑定配置文件(与xxxProperties绑定)指定的值。(也就是SpringBoot中自动配置类一般会利用EnableAutoConfiguration注解把配置文件中的属性封装到一个java bean类即xxxProperties中,利用这个封装类为其组件注入值)
- 生效的配置类给容器装配许多组件。
- 以用户配置的组件优先。
xxxAutoConfiguration --> 组件 -->xxxProperties取值 --> 配置文件修改(aplication.properties/yml)
@EnableConfigurationProperties(xxx.class):配置类中的组件通过该注解开启某个类的配置绑定功能,并将该类注册到容器。
@ConfigurationProperties(prefix = “xxx”):通过该注解与配置文件绑定,即在配置文件中通过该注解设置的前缀名修改的属性会对应作用于有配置功能的类中。
自动装配流程图: