- 首先分析SpringBoot的主启动类上的
@SpringBootApplicaion 注解@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}
)}
)
重点分析其中的@SpringBootConfiguration, @EnableAutoConfiguration,@ComponentScan注解。 @SpringBootConfiguration注解@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@Configuration代表当前的类是一个配置类。@ComponentScan:指定扫描哪些包。@EnableAutoConfiguration:@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY =
"spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
重点分析@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class) 。@AutoConfigurationPackage:自动配置包,指定了默认的包规则。 @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
- 首先,该注解给容器中导入了Registrar组件;
- 随后我们利用Registrat中的方法,获取当前注解标注的类的包名,并将该包下所有组件导入。
- 注解:该注解标注的类是MainApplication,所以所在包名就是主类所在的包,也正是因此而有的自动扫描包的功能。
@Import(AutoConfigurationImportSelector.class):利用AutoConfigurationImportSelector.class类下的getAutoConfigurationEntry(annotationMetadata)获取需要导入的组件名称,然后进行组件的批量导入
getAutoConfigurationEntry中先调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置名称,然后对其进行筛选后返回。getCandidateConfigurations方法内部利用工厂加载Map> loadSpringFactories(@Nullable ClassLoaderclassLoader);得到所有的组件名称并返回。loadSpringFactories方法内部其实就是加载META-INF/spring.factories位置的文件,默认会扫描们当前系统里面所有META-INF/spring.factories位置的文件,spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories,该文件中就写了所有了spring-boot一启动就要给容器中加载的配置类。
- 虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是
xxxxAutoConfiguration按照条件装配规则(@Conditional),最终会按需配置,整体装配的流程如下:
- SpringBoot先加载所有的自动配置类
xxxxxAutoConfiguration。 - 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值,生效的配置类就会给容器中装配很多组件,只要容器中有这些组件,相当于这些功能就有了。
- 自动配置类是否生效主要看是否符合
@Conditional注解条件。 - 同时还会利用
@EnableConfigurationProperties和@ConfigurationProperties为容器中注册一个包含指定配置的类,该类的属性值与application.properties从文件中取。 - 在该类下的组件就可以利用该配置类进行初始化(初始化方法中的参数会自动在容器中寻找符合条件的)并注册到容器中,此时也就具备了对应组件的功能。
- SpringBoot默认会在底层配置好所有组件,但是如果用户自己进行了配置,那么会以用户配置的优先。
- 组件:用户直接自己
@Bean替换底层的组件吗,如果用户自定义了组件,SpringBoot根据@Conditional注解就会选择用户自定义的组件。 - 配置:用户去看这个组件是获取的配置文件什么值就去修改。
- 注解:xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ---->application.properties。