springBoot的自动配置原理
Spring Boot自动配置解析
1.启动类核心(@SpringBootApplication)注解源码分析
该注解源码定义:
@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 {
// ...
}
该注解是SpringBoot应用的入口,它组合了多个关键注解,为自动配置提供基础
- 底层就是一个@import注解,导入Registrar类,该类会自动去调用registerBeanDefinitions方法,该方法中能够获取到引导类所在的包,配置@ComponentScan就可以让SpringBoot去扫描引导类包下的组件
2.自动配置核心流程详解
2.1 @EnableAutoConfiguration注解
@EnableAutoConfiguration注解是用来标记开启自动配置的注解
关键在于@Import(AutoConfigurationImportSelector.class),这是自动配置的入口点。
- 该注解导入一个
AutoConfigurationImportSelector
类,该类会自动调用selectImports
方法,方法内部会调用getAutoConfigurationEntry
方法,这个方法内部又会调用getCandidateConfigurations
方法,最终调用了SpringFactoriesLoader.loadFactoryNames
方法,这个方法会去加载autoconfigure.jar
包下META-INF
目录下的spring.factories
的配置文件,把key为EnableAutoConfiguration的值列表加载进内存,封装成一个字符串集合,再把集合转成一个字符串数组
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// ...
}
2.2 AutoConfigurationImportSelector核心方法
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取候选配置列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复配置
configurations = removeDuplicates(configurations);
// 处理排除的配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 应用条件过滤
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
// 获取候选配置列表
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
AutoConfigurationImportSelector通过getCandidateConfigurations获取到通过@ComponentScan扫描META-INF/spring.factories文件发现所有候选自动配置类,通过条件注解(@ConditionalOnXxx)智能判断哪些配置应该生效只有满足条件的配置才会被真正加载到Spring容器中
3.详细流程图及源码追踪
3.1 加载候选配置 - getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
ImportStrategy.IMMEDIATE.apply(configurations, this);
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
3.2 SpringFactoriesLoader.loadFactoryNames源码
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 扫描所有jar包中的META-INF/spring.factories文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 加载并解析配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName :
StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
3.3 条件过滤 - ConfigurationClassFilter
public class ConfigurationClassFilter {
private final ConditionEvaluator conditionEvaluator;
public Iterable<String> filter(Collection<String> classNames) {
// ...
for (String className : classNames) {
// 对每个候选配置类进行条件评估
if (isConfigurationCandidate(className)) {
// 使用ConditionEvaluator进行条件判断
if (this.conditionEvaluator.shouldSkip(metadataReader)) {
continue;
}
result.add(className);
}
}
return result;
}
}
3.4 ConditionEvaluator条件评估
public class ConditionEvaluator {
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// ...
// 获取所有@Conditional注解
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 按@Order排序
AnnotationAwareOrderComparator.sort(conditions);
// 逐个评估条件
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) &&
!condition.matches(this.context, metadata)) {
return true; // 条件不匹配,跳过该配置
}
}
return false;
}
}
4.典型条件注解实现
4.1 @ConditionalOnClass源码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
class OnClassCondition extends FilteringSpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 检查指定的类是否在类路径中存在
ConditionMessage matchMessage = ConditionMessage.empty();
if (matches(context, metadata)) {
return ConditionOutcome.match(matchMessage);
}
return ConditionOutcome.noMatch(matchMessage);
}
}
4.2 @ConditionalOnMissingBean源码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
String[] name() default {};
}
class OnBeanCondition extends BeanTypeRegistry implements ConfigurationCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 检查容器中是否不存在指定类型的Bean
// ...
}
}
5.自动配置类示例
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet")
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
// ...
}
完整流程总结
1.启动入口
@SpringBootApplication注解作为启动标记
内部包含@EnableAutoConfiguration开启自动配置功能
2.配置发现阶段
通过@Import(AutoConfigurationImportSelector.class)导入自动配置选择器
selectImports()方法作为配置加载入口
扫描所有依赖jar包中的META-INF/spring.factories文件
读取EnableAutoConfiguration键对应的配置类列表
3.配置处理阶段
去重处理:使用LinkedHashSet去除重复配置类
排除处理:根据exclude属性排除指定配置类
条件过滤:应用各种@Conditional条件注解进行智能筛选
4.条件注解体系
@ConditionalOnClass:类路径存在指定类才生效
@ConditionalOnMissingBean:容器中不存在指定Bean才生效
@ConditionalOnProperty:配置属性满足条件才生效
@ConditionalOnWebApplication:Web环境才生效
5.最终加载
通过Spring框架的标准流程处理筛选后的配置类
将配置类中的Bean定义注册到IoC容器
完成自动配置的最终目标