Spring Boot 3.x 自动配置详解

news2024/10/7 20:32:20

基于Spring Boot 3.1.0 系列文章

  1. Spring Boot 源码阅读初始化环境搭建
  2. Spring Boot 框架整体启动流程详解
  3. Spring Boot 系统初始化器详解
  4. Spring Boot 监听器详解
  5. Spring Boot banner详解
  6. Spring Boot 属性配置解析
  7. Spring Boot 属性加载原理解析
  8. Spring Boot 异常报告器解析
  9. Spring Boot 3.x 自动配置详解

Spring Boot :3.1
Java: 17

前言

Spring Boot 3.x 中的自动配置使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ,而不是META-INF/spring.factories,这个变动其实在2.7的时候已经改变

2.6.9版本文档介绍

在这里插入图片描述
2.7.0版本介绍

在这里插入图片描述
文档中有创建自己的Starter的详细介绍,《Spring Boot 中文参考指南-创建自己的自动配置》

加载原理

Spring Boot 3.x的自动配置加载入口是META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ,Spring Boot会读取该文件中的自动配置类,并实例化,我们以该文件为入口。

如果你是新手,并且没有资料可查,可以使用IDE的全局文件搜索功能,搜索关键词,如我搜索org.springframework.boot.autoconfigure.AutoConfiguration.imports 的结果如下,再通过打断点的方式就能判断加载该文件的入口。

在这里插入图片描述

可知,该文件的加载是由AutoConfigurationImportSelector类进行处理,但AutoConfigurationImportSelector类又是如何加载的。
通过断点的堆栈可知加载使用到了Spring 框架refresh()中的invokeBeanFactoryPostProcessors,其作用是在实例化Bean之前加载额外定义的Bean到上下文中,我们从头开始梳理,能力强的可以掌握方法自行阅读。

堆栈信息

在这里插入图片描述

AbstractApplicationContext-invokeBeanFactoryPostProcessors

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// 如果beanFactory中是否包含LoadTimeWeaver,如果包含则使用临时ClassLoader进行处理,LoadTimeWeaver是一种类加载器的动态织入技术
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

该方法的作用是:实例化并调用注册的BeanFactoryPostProcessor

getBeanFactoryPostProcessors() 用来获取所有的BeanFactoryPostProcessor实例,BeanFactoryPostProcessor实例通过ApplicationContextInitializer来加载到上下文中,ApplicationContextInitializer的加载原理可以通过前面的文章了解《Spring Boot 系统初始化器详解》。

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 委托处理BeanFactoryPostProcessor。

PostProcessorRegistrationDelegate-invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		Set<String> processedBeans = new HashSet<>();
		//如果beanFactory 是BeanDefinitionRegistry的实现,先处理BeanDefinitionRegistryPostProcessors
		if (beanFactory instanceof BeanDefinitionRegistry registry) {
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// 先处理 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor
			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);
			
//处理BeanDefinitionRegistryPostProcessors
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// 再处理 Ordered 的 BeanDefinitionRegistryPostProcessor
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			 // 最后处理剩余的 BeanDefinitionRegistryPostProcessor,直到没有新的 BeanDefinitionRegistryPostProcessor 添加为止
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// 处理所有 BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// 处理普通的上下文中的BeanFactoryPostProcessor
	invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		//获取所有常规化Bean,但不初始化,保留让后期的post-processors处理
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		
		//分离实现PriorityOrdered、Ordered和其他的BeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// 跳过已经处理的
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		
		//首先处理实现了PriorityOrdered的BeanFactoryPostProcessors
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		//处理实现了Ordered的BeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// 最后处理其他的BeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// 清除缓存
		beanFactory.clearMetadataCache();
	}

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); 是处理自动配置的关键点

PostProcessorRegistrationDelegate-invokeBeanDefinitionRegistryPostProcessors

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

//循环处理BeanDefinitionRegistryPostProcessor实现
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
	//步骤日志记录
		StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
				.tag("postProcessor", postProcessor::toString);
		postProcessor.postProcessBeanDefinitionRegistry(registry);
		postProcessBeanDefRegistry.end();
	}
}

BeanDefinitionRegistryPostProcessor接口继承了BeanFactoryPostProcessor接口,允许在初始化Bean实例之前修改、添加、删除容器中注册的Bean定义信息

在该示例的SpringBoot-Demo中,只有一个BeanDefinitionRegistryPostProcessor实现,即ConfigurationClassPostProcessor

ConfigurationClassPostProcessor-postProcessBeanDefinitionRegistry

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//计算hashcode
		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);

//处理配置Bean定义信息
		processConfigBeanDefinitions(registry);
	}

ConfigurationClassPostProcessor-processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//获取容器中所有的bean定义名称
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
		// 获取 bean 的定义
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// 检查该 bean 是否已经被处理成配置类
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// 检查该 bean 是否是配置类候选者
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// 如果没有需要处理的配置类,则直接返回
		if (configCandidates.isEmpty()) {
			return;
		}

		// 对配置类候选者进行排序,按照先前确定的 @Order 值排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// 检查是否有自定义的 bean 名称生成策略
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry _sbr) {
			sbr = _sbr;
			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();
		}

		// 解析每个 @Configuration 类
		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();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			//去除已经解析的类
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
// 检查新的 BeanDefinition 是否包含新的配置类候选者
			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = Set.of(candidateNames);
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// 注册 ImportRegistry 为一个 bean,以支持 @ImportAware ConfigurationClass
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		// 存储 PropertySourceDescriptors,便于在AOT中使用
		this.propertySourceDescriptors = parser.getPropertySourceDescriptors();

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory cachingMetadataReaderFactory) {
			// 清除缓存,防止由于缓存无法更新导致的出错问题
			cachingMetadataReaderFactory.clearCache();
		}
	}

此处代码很长,对于配置类的解析,在parser.parse(candidates)中完成。
parser变量的实例为:ConfigurationClassParser

ConfigurationClassParser-parse

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
			// 如果 BeanDefinition 是一个 AnnotatedBeanDefinition,则需要解析该 BeanDefinition 中的注解信息
				if (bd instanceof AnnotatedBeanDefinition annotatedBeanDef) {
					parse(annotatedBeanDef.getMetadata(), holder.getBeanName());
				}
				// 如果 BeanDefinition 不是 AnnotatedBeanDefinition,并且具有 beanClass 属性,则解析该 beanClass 中的注解信息
				else if (bd instanceof AbstractBeanDefinition abstractBeanDef && abstractBeanDef.hasBeanClass()) {
					parse(abstractBeanDef.getBeanClass(), holder.getBeanName());
				}
				else {
				// 如果 BeanDefinition 没有 beanClass 属性,则解析该 BeanDefinition 中的 beanClassName 所指定的类中的注解信息
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		
		//处理所有的DeferredImportSelector实例
		this.deferredImportSelectorHandler.process();
	}

在开始的时候,我们已经知道实际解析自动配置类是AutoConfigurationImportSelector,AutoConfigurationImportSelector 实现了DeferredImportSelector接口,而这里正好有deferredImportSelectorHandler来处理所有的deferredImportSelectorHandler实例。看下DeferredImportSelectorHandler中的process。

DeferredImportSelectorHandler-process

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<>();
			}
		}

DeferredImportSelectorGroupingHandler 类是在 Spring Boot 中处理 DeferredImportSelector 接口的辅助类,主要用于按照分组将DeferredImportSelector分组进行处理。

此处,我们要关注handler.processGroupImports(),调用到DeferredImportSelectorGroupingHandler类的processGroupImports方法。

DeferredImportSelectorGroupingHandler-processGroupImports

public void processGroupImports() {
			//遍历所有分组
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				//获取候选过滤器
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
				//遍历分组中的每个元素
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
					//处理当前元素
						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(),在这里对自动配置类进行了加载

DeferredImportSelectorGrouping-getImports

public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//处理每个分组的DeferredImportSelectorHolder
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	//返回需要导入的类
	return this.group.selectImports();
}

this.group.process中进入到AutoConfigurationImportSelector的内部类AutoConfigurationGroup

AutoConfigurationImportSelector-AutoConfigurationGroup-process

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()));
					
					//转为为AutoConfigurationImportSelector,获取AutoConfigurationEntry
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
		.getAutoConfigurationEntry(annotationMetadata);
	
//添加到autoConfigurationEntries变量中,供后期使用
this.autoConfigurationEntries.add(autoConfigurationEntry);
//设置entries变量,导入的类名和元注解映射关系
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

此处deferredImportSelector强转为AutoConfigurationImportSelector后,再次调用了getAutoConfigurationEntry方法。

AutoConfigurationImportSelector-getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 如果自动配置不可用,则返回 EMPTY_ENTRY
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	// 获取注解的属性
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	// 获取候选自动配置类,此文关键
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	// 去除重复的自动配置类
	configurations = removeDuplicates(configurations);
	// 获取需要排除的自动配置类,spring.autoconfigure.exclude配置
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
	// 检查是否有被排除的自动配置类
	checkExcludedClasses(configurations, exclusions);
	// 去除被排除的自动配置类
	configurations.removeAll(exclusions);
	// 使用 ConfigurationClassFilter 过滤自动配置类
	configurations = getConfigurationClassFilter().filter(configurations);
	// 发送自动配置事件
	fireAutoConfigurationImportEvents(configurations, exclusions);
	return new AutoConfigurationEntry(configurations, exclusions);
}

该方法的作用是根据给定的注解元数据获取自动配置项,对于自动配置的加载,关键在getCandidateConfigurations(annotationMetadata, attributes)

AutoConfigurationImportSelector-getCandidateConfigurations

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//从类路径的META-INF/spring中载入名为AutoConfiguration全限定名的类
	List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
		.getCandidates();
	Assert.notEmpty(configurations,
			"No auto configuration classes found in "
					+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
					+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

该方法的ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())会拼凑出META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports路径,用于加载定义的AutoConfiguration类。

ImportCandidates-ImportCandidates

public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
	Assert.notNull(annotation, "'annotation' must not be null");
	ClassLoader classLoaderToUse = decideClassloader(classLoader);
	//将META-INF/spring/%s.imports字符串格式化为指定的路径
	String location = String.format(LOCATION, annotation.getName());
	Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
	List<String> importCandidates = new ArrayList<>();
	while (urls.hasMoreElements()) {
		URL url = urls.nextElement();
		importCandidates.addAll(readCandidateConfigurations(url));
	}
	return new ImportCandidates(importCandidates);
}

grouping.getImports()获取到所有要导入的AutoConfigurationEntry后,通过processImports进行处理

ConfigurationClassParser-processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
        boolean checkForCircularImports) {

    // 如果没有可导入的类,则直接返回
    if (importCandidates.isEmpty()) {
        return;
    }

    // 检查循环导入
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        // 将当前配置类推入导入栈中
        this.importStack.push(configClass);
        try {
            // 处理每个导入的类
            for (SourceClass candidate : importCandidates) {
                if (candidate.isAssignable(ImportSelector.class)) {
                    // Candidate class is an ImportSelector -> delegate to it to determine imports
                    // 如果候选类是 ImportSelector 的子类,则交由它来决定导入哪些类
                    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 deferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);
                    }
                    else {
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    // 如果候选类是 ImportBeanDefinitionRegistrar 的子类,则交由它来注册更多的 Bean 定义
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                    this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    // 如果候选类不是 ImportSelector 或 ImportBeanDefinitionRegistrar 的子类,则将其作为 @Configuration 类来处理
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configClass.getMetadata().getClassName() + "]: " + ex.getMessage(), ex);
        }
        finally {
            this.importStack.pop();
        }
    }
}

MybatisPlusLanguageDriverAutoConfiguration自动配置为例,会通过processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);进行处理。

ConfigurationClassParser-processConfigurationClass

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);
			}
			// Otherwise ignore new imported config class; existing non-imported class overrides it.
			return;
		}
		else {
			// Explicit bean definition found, probably replacing an import.
			// Let's remove the old one and go with the new one.
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}

    // 递归地处理该配置类及其父类的继承关系,解析 Bean 定义
	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);

    // 将该配置类加入到 configurationClasses 中
	this.configurationClasses.put(configClass, configClass);
}
 

ConfigurationClassParser-doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// 如果该配置类被@Component注解标记,则递归处理任何嵌套类。
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 处理 @PropertySource
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.propertySourceRegistry != null) {
				this.propertySourceRegistry.processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 处理@ComponentScan注解
		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) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				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());
					}
				}
			}
		}

		// 处理@Import
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// 处理@ImportResource
		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);
			}
		}

		// 处理单个的@Bean方法
		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;
	}

总结

一张图说明整个自动配置加载解析流程
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/766550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(3)-再识Charles

1.简介 上一篇通过宏哥的介绍想必各位小伙伴或者童鞋们对Charles已经有了一个理性地认识&#xff0c;今天宏哥在从Charles的外貌介绍和分享一下&#xff0c;让小伙伴们或者童鞋们再对Charles有一个感性的认识&#xff0c;今天主要是对Charles的界面进行一个详细的介绍。 2.Ch…

CSS:给子元素设置了浮动,页面缩放的时候,子元素往下掉

前言 给子元素设置了浮动&#xff0c;页面缩放的时候&#xff0c;子元素往下掉 html代码&#xff1a; <div class"father"><div class"child1"></div><div class"child2"></div> </div>css代码 .child1…

SSD 读写擦相关知识

1. 简述闪存的工作原理及存储和记录数据 每个闪存芯片中有海量的存储单元&#xff08;Cell&#xff09;&#xff0c;下图是一个闪存存储单元的示意图&#xff0c;从上到下包括控制栅极、氧化层、浮栅层、隧道氧化层和衬底&#xff1b;左侧是源极&#xff0c;右侧是漏极。电流只…

【如何将无序知识库构建为结构化的语义知识库?《知识图谱:方法、工具与案例》将带你进入崭新的世界】

知识图谱开创了人工智能的新范式&#xff0c;以数据驱动和知识驱动相结合&#xff0c;开启了下一代人工智能&#xff0c;实现了人与人、人与机器、机器与机器的协同协作。此外&#xff0c;知识图谱突破了传统的人工智能研究领域&#xff0c;从广泛的文本、结构化、视觉和时序等…

WMS仓储管理系统项目实施,该如何调研

随着企业业务的不断发展&#xff0c;仓储管理逐渐成为企业竞争力的重要因素之一。为了提高仓储管理的效率和准确性&#xff0c;越来越多的企业选择引入WMS仓储管理系统解决方案。本文将探讨在WMS系统项目实施过程中&#xff0c;如何进行调研以确保项目的成功实施。 一、项目调研…

微信小程序上传图片报错:ReferenceError:that is not defined

微信小程序上传图片报错 问题背景 最近在开发一个微信小程序短视频项目&#xff0c;目前开发到用户中心模块&#xff0c;但是在实现头像上传功能时&#xff0c;头像上传成功&#xff0c;但是不能成功展示 报错ReferenceError:that is not defined 问题原因&#xff1a; 这个…

什么时间是投简历、面试的最佳时间?

什么时间投简历最好呢&#xff1f;面试是在上午好还是下午呢&#xff1f;相信大家在求职的过程中一定都思考过这些问题吧&#xff01;那么&#xff0c;投简历和面试是不是有最佳的时间呢&#xff1f;接下来&#xff0c;小编来告诉你投简历以及面试的最佳时间。 首先&#xff0…

Redis可视化工具(Redis Desktop Manager)

redis是我们平时开发工作中经常用到的非关系型数据库&#xff0c;常用于做数据缓存&#xff0c;分布式锁等。 为了更方便的使用redi&#xff0c;这里给大家推荐一款可视化工具&#xff1a;Redis Desktop Manager。 1.下载与安装 直接到gihub下载&#xff0c;地址 Release 0.…

集成AI的移动自动化测试

集成AI的 移动自动化测试 前一阵子小编看到了爱奇艺Android架构师的一篇文章《爱奇艺基于AI的移动自动化框架的设计与实践》。介绍了了一种基于AI算法的自动化测试框架Aion&#xff0c;该框架融合了传统图像处理和深度学习方案。虽然目前该框架还未开源&#xff0c;但是给了小…

行为式验证码(成语点选)(C#版和Java版)

一、先看效果图 二、背景介绍 图形验证码网上有挺多&#xff0c;比如&#xff1a;网易易盾、腾讯防水墙、阿里云验证码等等。参考了一下&#xff0c;自己实现了一个简单的成语点选的模式。 三、实现思路 1.选择若干张图片&#xff08;这里使用的是320x160的尺寸&#xff09;…

一篇搞懂steam/csgo搬砖原理

接触csgo游戏搬砖项目三年了&#xff0c;也有在别的论坛交流心得。让我无语的是有些已经游戏搬砖差不多半年&#xff0c;却还告诉我没有赚到钱&#xff0c;又或者说时常到可出售的时候利润少的可怕&#xff0c;总是说这个行业说水太深了&#xff01;那么请你告诉我&#xff0c;…

透过完美世界,再看游戏企业的主线价值

这段时间&#xff0c;游戏圈颇不平静。 虽说行业整体几家欢喜几家愁&#xff0c;但这至少反映出&#xff0c;版号发放常态化后&#xff0c;游企活力更足了&#xff0c;卯足了劲寻找突破点。 其中&#xff0c;相对于成熟作品带来的业绩成果&#xff0c;在研项目和新游表现实际…

JS:数组里面有多个子数组,想要获取每个子数组的第一个元素

前言 数组里面有多个子数组&#xff0c;想要获取每个子数组的第一个元素&#xff0c;例如&#xff1a;需要获取每个数组里面的水果 var data[["苹果", "猪","西兰花"],["草莓", "牛","黄瓜"],["樱桃"…

低代码或将颠覆开发行业?

文章目录 前言一、什么是低代码开发平台二、强大的平台总结 前言 传统的软件开发过程往往需要耗费大量的时间和精力&#xff0c;因为开发人员需编写复杂的代码以完成各种功能。 低代码行业的发展&#xff0c;正好解决了这个问题&#xff0c;让复杂的代码编写一去不复返了。 …

通过Windows WSL在GPU上运行tensorflow 2.12

背景 从tensorflow 2.10开始&#xff0c;已经没有tensorflow-gpu相应的版本在Window GPU运行了&#xff0c;只能通过在window上安装WSL2&#xff0c;在wsl2里运行tensorflow的方式调用GPU.当然你也可以回退到老的tensorflow-gpu的版本&#xff0c;不过你如果要用新的tensorflo…

go初识iris框架(二) - get,post请求和数据格式

继初步了解iris后 文章目录 获取url路径获取数据get请求post请求获取JSON数据格式JSON返回值获取XML数据格式XML返回值 获取url路径 package mainimport "github.com/kataras/iris/v12"func main(){app : iris.New()app.Get("/hello",func(ctx iris.Conte…

旅行社优惠卡小程序软件开发

旅游业的不断发展&#xff0c;越来越多的旅行社开始提供各种优惠卡小程序软件&#xff0c;以吸引更多的游客。这些小程序软件可以为游客提供各种优惠&#xff0c;例如门票折扣、酒店预订折扣、旅游线路折扣等等。 开发旅行社优惠卡小程序软件需要考虑以下几个方面&#xff…

java项目之贝儿米幼儿教育管理系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的贝儿米幼儿教育管理系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java…

Ceph 分布式应用2

一、创建 CephFS 文件系统 MDS 接口 1、服务端操作 1&#xff09;在管理节点创建 mds 服务 [rootadmin ceph]# cd /etc/ceph [rootadmin ceph]# ceph-deploy mds create node01 node02 node03 [ceph_deploy.conf][DEBUG ] found configuration file at: /root/.cephdeploy.c…

129、仿真-基于51单片机数字万用表测电压电流电阻仿真设计(Proteus仿真+程序+参考论文+配套资料等)

方案选择 单片机的选择 方案一&#xff1a;STM32系列单片机控制&#xff0c;该型号单片机为LQFP44封装&#xff0c;内部资源足够用于本次设计。STM32F103系列芯片最高工作频率可达72MHZ&#xff0c;在存储器的01等等待周期仿真时可达到1.25Mip/MHZ(Dhrystone2.1)。内部128k字节…