Spring Boot自动配置原理

 spring boot大大简化了spring里面的各种配置,那么它是如何自动加载各种配置的呢?通过源码分析

springboot项目都有一个主启动类,主启动类最重要的注解是@SpringBootApplication@SpringBootApplication又是由一系列注解组成的,大概的继承关系如下:

1
2
3
4
5
6
7
8
9
10
11
@SpringBootApplication

@EnableAutoConfiguration

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

​ ……

​ ……

 自动配置的核心功能又这两个注解完成:@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)

@AutoConfigurationPackage

 @AutoConfigurationPackage的内容如下:

1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}

@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}

}

 AutoConfigurationPackages.Registrar类中的registerBeanDefinitions(),功能是注册一个Bean的定义。**new PackageImport(metadata).getPackageName()**,返回了当前主程序类的 同级以及子级 的包组件。也就是main文件所在文件夹包及其下面所有的包。当程序进行ioc注入的时候,只会注入这些包下面被@Bean标注的对象。

@Import(AutoConfigurationImportSelector.class)

 AutoConfigurationImportSelector.class的源码如下,其中getAutoConfigurationEntry()方法实现了所有需要自动配置的类。

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

 getCandidateConfigurations()方法得到所有需要配置的候选类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
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 = filter(configurations, autoConfigurationMetadata);
//为配置类添加自动事件
//为不同的实例添加不同的类加载器
fireAutoConfigurationImportEvents(configurations, exclusions);
//new出和配置类数量相同的容器
return new AutoConfigurationEntry(configurations, exclusions);
}

 其中加载配置在函数getCandidateConfigurations();中,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	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;
}


public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}


private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//从META-INF/spring.factories加载配置文件
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
……

 SpringFactoriesLoader是Spring的一个工具类,功能是从指定的位置加载配置文件。因此,


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!