为什么就这一个注解,就可以让Spring Boot自动配置呢?
为了更清晰地阐述 Spring Boot 自动配置的底层原理,我们将结合源码进行更深入的分析,并加入一些关键步骤的代码片段。
注意:按住Ctrl键不松,点击相应注解,即可进入对应源码
1. @SpringBootApplication 注解的秘密:开启自动配置之旅
进入 @SpringBootApplication 注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 标明配置类
@EnableAutoConfiguration // 启用自动配置
@ComponentScan // 组件扫描
public @interface SpringBootApplication {
// ...
}
@SpringBootApplication 注解是 Spring Boot 的核心注解,它整合了三个关键注解:
-
@SpringBootConfiguration:声明该类为配置类,等同于 @Configuration。
-
@EnableAutoConfiguration:启用 Spring Boot 的自动配置机制。
-
@ComponentScan:启用组件扫描,自动发现和注册 Bean。
2. @EnableAutoConfiguration 深入剖析:AutoConfigurationImportSelector 的工作流程
@EnableAutoConfiguration 注解通过 @Import 注解导入 AutoConfigurationImportSelector:
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// ...
}
如下图:
AutoConfigurationImportSelector 实现了 ImportSelector 接口,其 selectImports() 方法是自动配置的核心逻辑:
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
importingClassMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
如下图:
selectImports() 方法主要完成以下步骤:
-
加载自动配置元数据: AutoConfigurationMetadataLoader.loadMetadata() 从 META-INF/spring-autoconfigure-metadata.properties 文件中加载自动配置元数据,用于优化自动配置的性能,例如基于条件评估的缓存。
-
获取自动配置入口: getAutoConfigurationEntry() 方法是核心逻辑所在,它负责获取所有候选的自动配置类。
private AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata importingClassMetadata) { if (!isEnabled(importingClassMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = EnableAutoConfiguration.get(importingClassMetadata); List<String> exclusions = getExclusions(importingClassMetadata, attributes); Set<String> configurations = getCandidateConfigurations(importingClassMetadata, attributes); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
- getCandidateConfigurations():通过 SpringFactoriesLoader.loadFactoryNames() 从 META-INF/spring.factories 文件中加载所有自动配置类名称。
- getExclusions():获取用户通过 exclude 属性或 excludeClass 属性排除的自动配置类。
- filter():根据 @Conditional 注解进行过滤,只保留符合条件的自动配置类. 其中会利用 ConditionEvaluator 来评估每个 @Conditional 注解。
- 最终返回 AutoConfigurationEntry 对象,其中包含了所有符合条件的自动配置类名称。
3. spring.factories 文件:自动配置类的清单
META-INF/spring.factories 文件中定义了 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的配置项,其 value 为一系列自动配置类的全限定名。
4. @Conditional 注解:精细化自动配置
4.1 问题:在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定义的配置类非常多,而且每个配置类中又可以定义很多的bean,那这些bean都会注册到Spring的IOC容器中吗?
答:并不是。 在声明bean对象时,上面有加一个以@Conditional开头的注解,这种注解的作用就是按照条件进行装配,只有满足条件之后,才会将bean注册到Spring的IOC容器中(下面会详细来讲解)
@Conditional 注解及其派生注解是 Spring Boot 自动配置的核心机制,用于根据各种条件判断是否加载某个自动配置类。
4.2 @Conditional
我们在跟踪SpringBoot自动配置的源码的时候,在自动配置类声明bean的时候,除了在方法上加了一个@Bean注解以外,还会经常用到一个注解,就是以Conditional开头的这一类的注解。以Conditional开头的这些注解都是条件装配的注解。下面我们就来介绍下条件装配注解。
@Conditional注解:
-
作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring的IOC容器中。
-
位置:方法、类
-
@Conditional本身是一个父注解,派生出大量的子注解:
-
@ConditionalOnClass:判断环境中有对应字节码文件,才注册bean到IOC容器。
-
@ConditionalOnMissingBean:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器。
-
@ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。
-
5. 自定义配置覆盖自动配置:控制加载顺序
@AutoConfigureBefore、@AutoConfigureAfter 和 @AutoConfigureOrder 注解可以控制自动配置类的加载顺序。
6. 自动配置源码小结
自动配置原理源码入口就是@SpringBootApplication注解,在这个注解中封装了3个注解,分别是:
-
@SpringBootConfiguration
-
声明当前类是一个配置类
-
-
@ComponentScan
-
进行组件扫描(SpringBoot中默认扫描的是启动类所在的当前包及其子包)
-
-
@EnableAutoConfiguration
-
封装了@Import注解(Import注解中指定了一个ImportSelector接口的实现类)
-
在实现类重写的selectImports()方法,读取当前项目下所有依赖jar包中META-INF/spring.factories、META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports两个文件里面定义的配置类(配置类中定义了@Bean注解标识的方法)。
-
-
当SpringBoot程序启动时,就会加载配置文件当中所定义的配置类,并将这些配置类信息(类的全限定名)封装到String类型的数组中,最终通过@Import注解将这些配置类全部加载到Spring的IOC容器中,交给IOC容器管理。
总结:自动配置流程再梳理
-
@SpringBootApplication 启动自动配置流程。
-
@EnableAutoConfiguration 导入 AutoConfigurationImportSelector。
-
AutoConfigurationImportSelector 的 selectImports() 方法加载候选配置类。
-
SpringFactoriesLoader 读取 META-INF/spring.factories 获取自动配置类列表。
-
@Conditional 注解及其派生注解根据条件过滤配置类。
-
符合条件的自动配置类被加载,并注册 Bean 到 Spring 容器。
-
自定义配置可以覆盖自动配置。
总体步骤如下:
通过深入源码,我们更清晰地理解了 Spring Boot 自动配置的原理和流程。 这有助于我们更好地利用 Spring Boot 的强大功能,并根据项目需求进行定制化配置。下期见,谢谢~
标签:Conditional,Java,SpringBoot,后端,Spring,配置,bean,自动,注解 From: https://blog.csdn.net/weixin_64178283/article/details/143058822