@SpringBootApplication
@SpringBootApplication注解由@SpringBootConfiguration、@EnabaleAutoConfiguration、@ComponentScan注解组成
有一些属性需要解释一下
exclude:禁用不需要自动装配的类
scanBasePackages:主类不在组件根包时,显示指定base的扫描包路径

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

使用@Import注解引入了AutoConfigurationImportSelector.class@ComponentScan
自动扫描当前类所在的包及其子包中的组件(使用@Controller、@Service、@Component等),并注册为Bean,注入到Spring容器中
AutoConfigurationImportSelector
@EnableAutoConfiguration注解中使用import引入了AutoConfigurationImportSelector
核心入口方法:selectImports
1 |
|
- 判断是否开启自动配置
- 加载所有自动配置类
- 返回要自动配置的全类名数组
关键方法:getAutoConfigurationEntry
1 | protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { |
获取所有候选自动配置类
默认从jar包的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中获取需要的自动装配类
去重
将第一步得到的list转换为LinkedHashSet,再转换回list
拿到要排除的配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24private 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排除类
校验需要排除的配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23private 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));
}- 需要校验排除的类必须存在
- 需要校验排除的类 必须是配置类
为什么要校验?用户排除类后肯定想配置类不注入,如果排除类写错了,很影响排查问题
移除被排除的类
过滤
1
2
3
4
5
6
7
8
9
10
11
12private 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,值就是要根据注解过滤的配置类

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