Spring Boot 自动配置的原理
SpringBoot 使用起来非常方便,核心就在于自动配置,接下来分析一下SpringBoot自动配置的实现原理。
(2.4.1)
@SpringBootApplication
这是 SpringBoot 主类上的注解,来看一下它的源码:
@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 {
// .....
}
它由主要的三个注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 构成。
下面单独分析三个注解。
@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
与 @Configuration 功能相同:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
@ComponentScan
扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
@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 {};
}
@Import({AutoConfigurationImportSelector.class})
就是实现自动配置的关键。
通过 AutoConfigurationImportSelector
,@EnableAutoConfiguration
可以将符合条件的 @Configuration 配置类都加载到 IoC容器中。
那么配置类在哪?符合条件又是什么意思?
- 加载哪些配置类?
在AutoConfigurationImportSelector
有这样一个方法,
它会去查找**所有依赖的 jar 包(不止 spring-boot-autoconfigure-2.4.1.jar)**中的 META-INF/spring.factories。
这是 spring-boot-autoconfigure-2.4.1.jar 中的 spring.factories:
从这些 spring.factories 中,加载 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
的所有配置类到 List 中,
spring.factories文件里每一个xxxAutoConfiguration文件一般都会有下面的条件注解:
@ConditionalOnClass : classpath中存在该类时起效
@ConditionalOnMissingClass : classpath中不存在该类时起效
@ConditionalOnBean : DI容器中存在该类型Bean时起效
@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效
@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效
@ConditionalOnExpression : SpEL表达式结果为true时
@ConditionalOnProperty : 参数设置或者值一致时起效
@ConditionalOnResource : 指定的文件存在时起效
@ConditionalOnJndi : 指定的JNDI存在时起效
@ConditionalOnJava : 指定的Java版本存在时起效
@ConditionalOnWebApplication : Web应用环境下起效
@ConditionalOnNotWebApplication : 非Web应用环境下起效
接下来会根据这些类的条件注解,决定哪些类是生效的类。
一个条件注解示例:
实例
准备 jar 包
目的:
- 验证 SpringBoot 的自动配置功能是否可以加载其他 jar 包下的 spring.factories.
- 是否加载 spring.factories 中的 key 不为
org.springframework.boot.autoconfigure.EnableAutoConfiguration
的配置类。
步骤:
创建一个工程,在 resources 目录下添加 META-INF/spring.factories,
在 spring.factories 中一个类的 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
,
另一个类的key 为 org.springframework.boot.diagnostics.FailureAnalyzer
。
一会儿打成 jar 包,导入到 SpringBoot 工程中。
导入 SpringBoot 工程验证
在 AutoConfigurationImportSelector
中打个断点,我们就能够看到 entity.PersonTest
已经被导入进来了。
根据以上结果,得出初步结论:
- SpringBoot 的自动配置功能可以加载其他 jar 包下的 META-INF/spring.factories.
- 只加载 spring.factories 中的 key 为
org.springframework.boot.autoconfigure.EnableAutoConfiguration
的配置类。