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.详细流程图及源码追踪

graph TD A[SpringBootApplication启动] --> B[EnableAutoConfiguration] B --> C[Import导入选择器] C --> D[selectImports调用] D --> E[获取配置项] E --> F[获取注解属性] E --> G[加载候选配置] G --> G1[SpringFactoriesLoader] G1 --> G2[扫描配置文件] E --> H[去重处理] E --> I[获取排除项] E --> J[验证排除项] E --> K[移除排除项] E --> L[创建过滤器] L --> M[条件过滤] M --> N[发布事件] N --> O[返回配置数组] O --> P[Spring容器处理] P --> Q[注册Bean]

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容器
完成自动配置的最终目标

posted @ 2025-08-21 21:29  mz456  阅读(14)  评论(0)    收藏  举报