我们从启动类里的@SpringBootApplication注解开始
里面有三个主要注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
这里自动装配的主要注解是@EnableAutoConfiguration这个,我们跟进去看看
会发现这里面有引入我们上章提到的神秘东东AutoConfigurationImportSelector
继续跟进AutoConfigurationImportSelector一探究竟,它是实现DeferredImportSelector,这个里面继承了ImportSelector
我们来看看他的selectImports方法实现
@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());
}
这里面我们关注getAutoConfigurationEntry继续跟进去
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
继续跟进getCandidateConfigurations这个方法
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List 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;
}
到这里你会发现有这么句话No auto configuration classes found in META-INF/spring.factories,
META-INF/spring.factories这个文件是不是有点熟悉,先放着,继续跟进就会明白了
public static List loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
直到这里你会发现,他就是加载了所有META-INF/spring.factories文件下的数据,我们随便点开一个META-INF/spring.factories看看
这里面就有很多需要自动装配的key-value对,到这里我们就应该能猜到大概实现了
这里loadFactoryNames就是获取对应EnableAutoConfiguration.class也就是对应上面spring.factories文件里的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有value值也就是class路径
protected Class> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
我们重新回到selectImports方法
到这里我们就很清楚这里返回的就是所有在spring.factories文件里key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有value值class路径,印证上一章中的例子,我们下面回顾下:
同样这里是不是可以启发我们,将配置类写在META-INF/spring.factories文件里,然后key写为
org.springframework.boot.autoconfigure.EnableAutoConfiguration
是不是也可以自动帮我们给装配进去,例如下面这样我们在自己项目中创建META-INF/spring.factories,我们自动装配UserA
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.service.UserA
这样我们也是一样可以在spring容器中可以拿到我们的UserA;
ok,基本的实现流程我们已经了解大概了,那到这里应该还是会有个疑问,哪个地方调用selectImports方法?
下章我们就这个问题进行分析