springboot 初始加载自动配置类
Posted 霜序0.2℃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot 初始加载自动配置类相关的知识,希望对你有一定的参考价值。
springboot 初始加载自动配置类
@SpringBootApplication --> @EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage
只是指定了包,并获取信息封装到数组里
在EnableAutoConfiguration
源码中有@Import
我们打开AutoConfigurationImportSelector
源码中有一个方法:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
返回值是一个字符串数组,即要导入的组件的名字
如果annotationMetadata
存在,那么从this.getAutoConfigurationEntry(annotationMetadata);
,中文翻译即通过注解变化信息自动找到配置入口,最终得到所有配置并通过StringUtils.toStringArray
封装返回
再来看看getAutoConfigurationEntry
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
这个方法通过List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取到所有需要导入到容器的配置类
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
我们可以看到第一行有一个spring工厂加载器
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
点进SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
我们看return的loadSpringFactories
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader)
返回的是一个Map,用来加载所有组件
看它完整的源码:
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
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[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
我们可以看到有一行Enumeration urls = classLoader.getResources("META-INF/spring.factories");
相当于从这个文件META-INF/spring.factories
中扫描
那么这个文件在哪呢?连包名都没有,我们到导入的jar里找,有些没有这个文件,有些有,打开spring-boot-2.5.5.jar
下我们发现了文件,然后我们还发现spring-boot-autoconfigure-2.5.5.jar
包下面也有这个文件
一个是默认启动类配置包(就是初始化之类的),一个是加载所需的100多个组件包
在spring-boot-autoconfigure-2.5.5.jar/META-INF/spring.factories
中发现了
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
也就是EnableAutoConfiguration
注解,注解要加载哪些类,就从这里进入
然后我们在后面也可以看到,后缀都是xxxAutoConfiguration
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\\
文件里面写死了一启动就要给容器中加载的所有配置类
按需加载
当然其实也不是一开始全部加载,我们需要按需开启,springboot中有个组件条件依赖的注解ConditionalXXX
,例如:ConditionalOnClass
,在类路径里面有某个类才生效,只有导入这个包才生效
以上是关于springboot 初始加载自动配置类的主要内容,如果未能解决你的问题,请参考以下文章