一、背景
??你真的了解Spring Boot 自动装配的原理么?很多小伙伴就直接开始从主类上的注解@SpringBootApplication 开始点击,然后一直点击到类org.springframework.boot.autoconfigure.AutoConfigurationImportSelector,然后会执行哪里哪里,估计也是人云亦云,有没有想过为啥会要走@SpringBootApplication ?什么时候走?好了,废话不多少,我们来探索真正的自动装配原理。
1.1、主类的加载
??其实我在之前的文章Alian解读SpringBoot 2.6.0 源码(七):启动流程分析之准备应用上下文 就讲到了很重要的一部分知识,那就是主类资源的加载和注册。希望大家看完我下图标注的,再看下去会比较容易理解。
1.2、后置处理器的获取
??同样的我在之前的文章Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(中) 就讲到了后置处理器ConfigurationClassPostProcessor 的获取,具体如下图: ??认真理解我所说的这两个点后,开始我们的解读,因为这些我在之前的文章就已经解读很细了,这里只是引用而已,具体的还是需要大家自己认真调试到这里,具体的代码如下:
final class PostProcessorRegistrationDelegate {
private PostProcessorRegistrationDelegate() {
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
} else {
}
}
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}
}
??因为postProcessors得到就只有一个对象,那就是ConfigurationClassPostProcessor ,接下里我们就去看看是如何一步步调用的。
二、配置类后处理器
2.1、获取配置类
??具体的类路径:org.springframework.context.annotation.ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware{
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
parser.parse(candidates);
parser.validate();
}
while (!candidates.isEmpty());
}
}
??而得到的candidateNames就是如下列表:
- org.springframework.context.annotation.internalConfigurationAnnotationProcessor
- org.springframework.context.annotation.internalAutowiredAnnotationProcessor
- org.springframework.context.annotation.internalCommonAnnotationProcessor
- org.springframework.context.event.internalEventListenerProcessor
- org.springframework.context.event.internalEventListenerFactory
- springbootApplication
- org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
??实际上倒数第二个就是我们的主类
package com.alian.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
- 获取注册表中定义的所有bean的名称列表
- 遍历候选列表,如果是配置类则加入待解析的列表,此过程里面会扫描类的注解及父注解
- 把获取到的列表按照order排序,实际上就只有我们的主类springbootApplication
- 创建一个新的ConfigurationClassParser实例,然后解析每个@Configuration类
2.2、
??具体的类路径:org.springframework.context.annotation.ConfigurationClassParser
class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
}
这里有两个重要步骤
- 解析我们的主类
- Import Select 处理程序的执行
2.3、解析主类
2.3.1、整体解析过程
??同样的具体的类路径:org.springframework.context.annotation.ConfigurationClassParser,我们先看看主类的解析。
class ConfigurationClassParser {
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
} else {
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
}
- 根据@Conditional 注解确定是否应跳过项
- 从已解析的map中获取对象,并判断该配置类是否已解析过
- 递归处理配置类及其超类层次结构
- 把解析的配置类放到已解析的map中
2.3.2、核心解析过程
??我继续看下doProcessConfigurationClass方法,同样的具体的类路径还是:org.springframework.context.annotation.ConfigurationClassParser
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
processMemberClasses(configClass, sourceClass, filter);
}
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
processInterfaces(configClass, sourceClass);
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
return null;
}
- 如果有@Component 注解,递归处理任何成员(嵌套)类
- 处理带@PropertySource 注解的类
- 处理带@ComponentScan注解的类,这里可能会递归
- 处理带@Import 注解的类
- 处理带@ImportResource 注解的类
- 处理单个@Bean 方法
- 处理接口上的默认方法
- 如果有父类则处理父类,没有则处理完成
2.3.3、延迟导入选择器处理程序
??我继续看下DeferredImportSelectorHandler的process()方法,它是:org.springframework.context.annotation.ConfigurationClassParser的内部类
class ConfigurationClassParser {
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
private class DeferredImportSelectorHandler {
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
}
- 获取延迟导入选择器,其实在解析阶段处理带@Import 注解的类时就初始化了DeferredImportSelectorHolder到列表deferredImportSelectors 中了,我们的EnableAutoConfiguration 也是有@Import 注解的,自然
AutoConfigurationImportSelector就是被扫描注入了(这个很关键哦)
@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 {};
}
- 遍历延迟导入选择器分组处理程序,调用register方法,此步骤会获取导入组,实际就是实现了DeferredImportSelector接口类,而上面我们注入的导入的类AutoConfigurationImportSelector就是实现了DeferredImportSelector接口,从而返回了导入组AutoConfigurationGroup.class,而它是AutoConfigurationImportSelector的一个内部类
- 延迟导入选择器分组处理程序的执行
2.3.4、延迟导入选择器分组处理程序的注册和执行
private class DeferredImportSelectorGroupingHandler {
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
public void register(DeferredImportSelectorHolder deferredImport) {
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
});
}
}
}
注册时:
- deferredImport.getImportSelector()获得AutoConfigurationImportSelector
- 然后调用getImportGroup()得到AutoConfigurationGroup.class
- 创建DeferredImportSelectorGrouping 的实例,并组装映射
- 配置类映射中存放延迟导入的配置类的元数据和延迟导入的配置类的映射
执行时:
- 从上面的注册知道遍历的groupings里就是AutoConfigurationImportSelector
- 然后执行DeferredImportSelectorGrouping的getImports()
class ConfigurationClassParser {
private static class DeferredImportSelectorGrouping {
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
}
}
??关键方法 process 第一个参数就是元数据 ,这里的值是:com.alian.springboot.SpringbootApplication ;第二个参数是延迟导入选择器 ,这里的值是:AutoConfigurationImportSelector ,然后调用AutoConfigurationImportSelector的 process方法,这样才是真的进入到这个类的执行。
2.4、自动配置获取
2.4.1、自动配置组执行
AutoConfigurationImportSelector.java
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
private static class AutoConfigurationGroup
implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
}
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);
}
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;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
}
?? process方法主要还是调用核心的方法 getAutoConfigurationEntry,我们说下它大概的流程:
- 获取注解元数据上的注解属性
- 根据元数据和注解属性获取候选配置类(核心方法)
- 移除重复配置类
- 获得注解元数据中被exclude和excludeName排除的类的集合
- 检查被排除的类,在候选配置类中去除掉被排除的类,并过滤配置类
- 将配置类和排除类通过事件传入到监听器中
- 返回符合条件的自动配置类的全限定名数组
2.4.2、loadFactoryNames
??此方法所在类的具体路径:org.springframework.core.io.support.SpringFactoriesLoader
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
- loadSpringFactories(ClassLoader classLoader)返回的是所有META-INF/spring.factories文件解析完的结果
- 根据指定类名获取结果,没有则返回空列表
2.4.3、loadSpringFactories
??此方法所在类的具体路径:org.springframework.core.io.support.SpringFactoriesLoader
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
}
??因为SpringApplication实例化时就加载过一次了,这里就是从缓存中获取到值了,讲到这里我想就不用我多讲了,结合我之前的文章Alian解读SpringBoot 2.6.0 源码(一):SpringApplication对象创建(Spring工厂加载机制)就完全清楚了,我这篇文章里把超级详细的加载过程都讲解了,这里就不在占用篇幅了。只不过本文中就是加载实现了org.springframework.boot.autoconfigure.EnableAutoConfiguration 的类而已。也就是从META-INF/spring.factories文件中获取EnableAutoConfiguration的实现类,我这个版本是133个,最终符合条件的配置类就是24个:
- org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
- org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
- org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
- org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
- org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
- org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
- org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
- org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
- org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
- org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
- org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
- org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
- org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
- org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
- org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
- org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
- org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
??这个时候就得到了需要进行自动装配的类了,章节2.3.4后面有个调用(this.group.selectImports())返回每个导入及其关联的配置类,它调用的就是AutoConfigurationGroup 的selectImports()方法,后续遍历结果,一个个执行导入的配置类,完成最后的自动配置操作。
结语
??从这里看到,我们只需要把要加载的类配置到META-INF/Spring.factories 文件里,SpringBoot 会自动去加载它,很方便我们自己或者是第三方去扩展,我们也可以实现自己 starter,我之前写Alian 的 Spring Cloud就写了很多的starter。
|