1. 1. @SpringBootApplication
  2. 2. AutoConfigurationImportSelector
    1. 2.1. 核心入口方法:selectImports
    2. 2.2. 关键方法:getAutoConfigurationEntry

@SpringBootApplication

@SpringBootApplication注解由@SpringBootConfiguration、@EnabaleAutoConfiguration、@ComponentScan注解组成

有一些属性需要解释一下

exclude:禁用不需要自动装配的类

scanBasePackages:主类不在组件根包时,显示指定base的扫描包路径

image-20260514215106550

  • @SpringBootConfiguration
    本质是Configuration的变体,标记当前类为配置类,允许通过@Bean定义组件

  • @EnableAutoConfiguration

    image-20260514215154291
    使用@Import注解引入了AutoConfigurationImportSelector.class

  • @ComponentScan
    自动扫描当前类所在的包及其子包中的组件(使用@Controller、@Service、@Component等),并注册为Bean,注入到Spring容器中

AutoConfigurationImportSelector

@EnableAutoConfiguration注解中使用import引入了AutoConfigurationImportSelector

核心入口方法:selectImports

1
2
3
4
5
6
7
8
9
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

  1. 判断是否开启自动配置
  2. 加载所有自动配置类
  3. 返回要自动配置的全类名数组

关键方法:getAutoConfigurationEntry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 1. 获取所有候选自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

// 2. 去重
configurations = removeDuplicates(configurations);

// 3. 拿到要排除的配置类(exclude)
Set<String> exclusions = getExclusions(annotationMetadata, attributes);

// 4. 校验排除类
checkExcludedClasses(configurations, exclusions);

// 5. 移除被排除的
configurations.removeAll(exclusions);

// 6. 过滤(条件注解过滤 @Conditional)
configurations = getConfigurationClassFilter().filter(configurations);

// 7. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);

return new AutoConfigurationEntry(configurations, exclusions);
}
  1. 获取所有候选自动配置类
    默认从jar包的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中获取需要的自动装配类
    image-20260514230220033

  2. 去重
    将第一步得到的list转换为LinkedHashSet,再转换回list
    image-20260514230326939

  3. 拿到要排除的配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

    protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    Set<String> excluded = new LinkedHashSet<>();
    excluded.addAll(asList(attributes, "exclude"));
    excluded.addAll(asList(attributes, "excludeName"));
    excluded.addAll(getExcludeAutoConfigurationsProperty());
    return excluded;
    }

    protected List<String> getExcludeAutoConfigurationsProperty() {
    Environment environment = getEnvironment();
    if (environment == null) {
    return Collections.emptyList();
    }
    if (environment instanceof ConfigurableEnvironment) {
    Binder binder = Binder.get(environment);
    return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class)
    .map(Arrays::asList)
    .orElse(Collections.emptyList());
    }
    String[] excludes = environment.getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
    return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
    }

    getExclusions 从3个地方排除配置类:

    • ①exclude指定的排除类.class
    • ②excludeName指定的全路径类名
    • ③根据getExcludeAutoConfigurationsProperty获取application.yaml配置的spring.autoconfigure.exclude排除类
  4. 校验需要排除的配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
    List<String> invalidExcludes = new ArrayList<>(exclusions.size());
    for (String exclusion : exclusions) {
    // 如果类不存在 或者 这个类根本不是配置类,则加入校验失败队列
    if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
    invalidExcludes.add(exclusion);
    }
    }
    // 校验失败队列非空,抛出报错
    if (!invalidExcludes.isEmpty()) {
    handleInvalidExcludes(invalidExcludes);
    }
    }

    protected void handleInvalidExcludes(List<String> invalidExcludes) {
    StringBuilder message = new StringBuilder();
    for (String exclude : invalidExcludes) {
    message.append("\t- ").append(exclude).append(String.format("%n"));
    }
    throw new IllegalStateException(String.format(
    "The following classes could not be excluded because they are not auto-configuration classes:%n%s",
    message));
    }
    • 需要校验排除的类必须存在
    • 需要校验排除的类 必须是配置类
    • 为什么要校验?用户排除类后肯定想配置类不注入,如果排除类写错了,很影响排查问题
  5. 移除被排除的类

  6. 过滤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    private ConfigurationClassFilter getConfigurationClassFilter() {
    // 只创建一次,保证单例
    if (this.configurationClassFilter == null) {
    // 加载过滤器(核心)
    List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
    for (AutoConfigurationImportFilter filter : filters) {
    invokeAwareMethods(filter);
    }
    this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
    }
    return this.configurationClassFilter;
    }

    getAutoConfigurationImportFilters 去所有jar包中读取:spring.factories里面的内容,key为AutoConfigurationImportFilter,值就是要根据注解过滤的配置类

    image-20260515223556250

  7. 触发自动配置导入事件

    • 记录哪些自动配置被导入
    • 记录哪些被排除
    • 最后输出控制台报告(DEBUG 模式可见)