加载spring.factories
springBoot启动时,会创建SpringApplication。进入其构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这里会调用org.springframework.boot.SpringApplication#getSpringFactoriesInstance
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
最终会进入
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
try {
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;
}
}
这个方法的逻辑为从classpath下面读取META-INF/spring.factories下的文件。可能有很多个
按照键值对的方式读取,最终放到cache中,key为类型,value为一个集合存储了配置文件里的内容
形式为
后续如果需要获取某个类型,直接从缓存中根据类型获取就好了
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
创建配置类实例
spring.factories里存放了各种springBoot所需的接口
这里举例例如springBoot监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
会从spring.factories中获取
调用org.springframework.boot.SpringApplication#getSpringFactoriesInstances方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
从cache中获取到这个类型的所有配置并且都创建实例,后会进行排序
AnnotationAwareOrderComparator.sort(instances);
根据@Order注解和PriorityOrdered接口进行排序
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
两个原则继承PriorityOrdered靠前,Order注解越小越靠前
如果没有order注解,那么会给默认一个人整数最大值,排名靠后
后续就可以使用这些实例进行在适当的时机调用
EnableAutoConfiguration
EnableAutoConfiguration是springBoot自动装配的核心,也是开发最经常使用到的
通常使用会这么配置
那么springBoot是如何加载他们的
@SpringBootApplication注解中上默认有@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
其中有@Import(AutoConfigurationImportSelector.class)
那么在扫描bean时也会把AutoConfigurationImportSelector扫描到并加载
那么看这个关键类
AutoConfigurationImportSelector
ImportSelector
先看其接口
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
default Predicate<String> getExclusionFilter() {
return null;
}
}
ImportSelector介绍
在@Configuration标注的Class上可以使用@Import引入其它的配置类,其实它还可以引入org.springframework.context.annotation.ImportSelector实现类。ImportSelector接口只定义了一个selectImports(),用于指定需要注册为bean的Class名称。当在@Configuration标注的Class上使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。来看一个简单的示例,假设现在有一个接口HelloService,需要把所有它的实现类都定义为bean,而且它的实现类上是没有加Spring默认会扫描的注解的,比如@Component、@Service等。
例如
public class HelloImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {HelloServiceA.class.getName(), HelloServiceB.class.getName()};
}
}
@Configuration
@Import(HelloImportSelector.class)
public class HelloConfiguration {
}
DeferredImportSelector
DeferredImportSelector是ImportSelector的一个扩展;
在一个配置类中
ImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!);
DeferredImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
DeferredImportSelector的实现类可以用Order注解,或者实现Ordered接口来对selectImports的执行顺序排序;
ImportSelector与DeferredImportSelector区别分析
DeferredImportSelector 的预处理
在org.springframework.context.annotation.ConfigurationClassParser#processImports方法中
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
如果扫描到的bean是ImportSelector类型的。那么实例化这个selector
如果不是DeferredImportSelector
那么直接调用selector.selectImports方法 返回的类会被扫描为bean
如果是DeferredImportSelector
那么调用this.deferredImportSelectorHandler.handle方法
// ConfigurationClassParser.DeferredImportSelectorHandler#handle
// deferredImportSelectors 保存待处理的 Selector
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
// configClass 是持有该@Import 注解的 配置类, importSelector 是引入的 DeferredImportSelector
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
// 将 DeferredImportSelector 和其引入的配置类保存起来。
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
// 如果deferredImportSelectors 为空,则重新注册
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
// 将当前的 config 和 Selector 的持有者保存起来
this.deferredImportSelectors.add(holder);
}
}
当在@Configguration注解中的一个配置类其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理全部处理完毕之后(parse方法结束)
才会调用process方法
DeferredImportSelector 的真正处理
在 ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>) 中最后一句处理了 DeferredImportSelector
this.deferredImportSelectorHandler.process();
public void process() {
// 获取待处理的 DeferredImportSelectorHolder
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 1. 根据不同的group 进行分组注册
deferredImports.forEach(handler::register);
// 2. 按照分组调用
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
如果有多个deferredImports,那么会排序并且分执行对应的register方法
handler::register
这里有两步操作 :
- 将不同的 DeferredImportSelectorHolder 按照分组进行划分
- 将DeferredImportSelectorHolder 的信息保存到 configurationClasses 中。(供后面调用的时候获取)
public void register(DeferredImportSelectorHolder deferredImport) {
// 获取当前 DeferredImportSelector 的Group
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 将当前 DeferredImportSelector 添加到同一分组中的
grouping.add(deferredImport);
// 保存需要处理的配置类
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
handler.processGroupImports()
这一步根据不同分组将分组中的 DeferredImportSelector 引入的类通过 entry.getImportClassName() 来包装后,调用 processImports 方法进行了新一轮解析。
public void processGroupImports() {
// 遍历每个分组
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 获取分组的过滤器
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
// 遍历分组中所有的 Entry (封装了需要引入的类的信息)
grouping.getImports().forEach(entry -> {
// 从 configurationClasses 集合中获取到对应的 ConfigurationClass 。其中保存
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
// 对 configurationClass 进行解析。这里的解析在 ConfigurationClassPostProcessor 文章已经有过解释。
// entry.getImportClassName() 获取到了引入的类
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
其中 grouping.getImports() 的实现如下
// org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
// 调用 DeferredImportSelector.Group#process
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
// 调用 DeferredImportSelector.Group#selectImports
return this.group.selectImports();
}
我们这里调用的是 DefaultDeferredImportSelectorGroup
private static class DefaultDeferredImportSelectorGroup implements Group {
private final List<Entry> imports = new ArrayList<>();
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
// 调用了ImportSelector#selectImports 方法
for (String importClassName : selector.selectImports(metadata)) {
this.imports.add(new Entry(metadata, importClassName));
}
}
@Override
public Iterable<Entry> selectImports() {
// 直接将 Imports 返回
return this.imports;
}
}
综上可以看到 DeferredImportSelector 的处理过程并非是直接 调用ImportSelector#selectImports方法。而是调用 DeferredImportSelector.Group#process 和 Group#selectImports 方法来完成引入功能。
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);
}
从spring.factories中 配置为org.springframework.boot.autoconfigure.EnableAutoConfiguration排除需要排除掉的之后 都会被加载出来,注册成bean