3自动配置流程源码

目录

1加载AutoConfigurationImportSelector

2加载自动配置类

3过滤自动配置类

4实例化自动配置类

5ConfigurationClassParser类

6条件注解


1加载AutoConfigurationImportSelector

自动化配置的逻辑,入口为refresh()中:

public void refresh() throws BeansException, IllegalStateException {
        //...
        invokeBeanFactoryPostProcessors(beanFactory);
        //...
    }

@SpringBootApplication含有@EnableAutoConfiguration,

@EnableAutoConfiguration含有@Import(AutoConfigurationImportSelector.class),

会在

invokeBeanFactoryPostProcessors(beanFactory);

时被ConfigurationClassParser的processImports加载到容器。

2加载自动配置类

在ConfigurationClassParser类的parse()方法中,执行

this.deferredImportSelectorHandler.process();

最终解析spring.factories文件:

@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(getAutoConfigurationMetadata(),
							annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

 

protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			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 = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

 

3过滤自动配置类

private List<String> filter(List<String> configurations,
	...
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			invokeAwareMethods(filter);
			boolean[] match = filter.match(candidates, autoConfigurationMetadata);
			for (int i = 0; i < match.length; i++) {
				if (!match[i]) {
					skip[i] = true;
					candidates[i] = null;
					skipped = true;
				}
			}
		}
	...
	}

getAutoConfigurationImportFilters()从spring.factoris中加载

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
				this.beanClassLoader);
	}

4实例化自动配置类

和所有单例bean一起在refresh()方法的

finishBeanFactoryInitialization(beanFactory);

中进行实例化

5ConfigurationClassParser类

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		// Process any @PropertySource annotations
		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");
			}
		}

		// Process any @ComponentScan annotations
		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());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				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());
					}
				}
			}
		}

		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		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);
			}
		}

		// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

这个方法的入口在refresh的

invokeBeanFactoryPostProcessors(beanFactory);

该方法的作用是

解析基于注解的Configuration类,获取beanDefinition,并注册进了容器,等待实例化。

参考:spring容器加载分析 三Configuration类解析

6条件注解

@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)

 

 

 

 

 

 

 

 

 

 

 

 

<think>嗯,用户让我介绍一下Spring Boot的自动配置和启动流程的核心源码理解。首先,我需要确认用户的需求是什么。他们可能正在学习Spring Boot,想要深入了解其内部工作原理,特别是自动配置和启动过程。用户可能已经有一些基础,但需要更详细的源码层面的解释,而不仅仅是概念。 接下来,我要考虑从哪里开始。自动配置是Spring Boot的核心特性之一,它基于条件注解来配置Bean。我需要回忆一下相关的核心类,比如@EnableAutoConfiguration,AutoConfigurationImportSelector,以及spring.factories文件的作用。这部分需要解释自动配置是如何被触发和加载的。 然后是启动流程,这部分涉及到SpringApplication类的run方法。用户可能想知道从启动到应用完全运行的过程中,各个阶段都做了什么。比如准备环境、创建应用上下文、加载Bean定义,最后启动Tomcat等嵌入式服务器。需要分解每个步骤,并提到关键的方法,比如refreshContext和onRefresh。 用户可能需要具体的例子或者源码片段来说明这些过程。例如,在自动配置中,如何通过spring.factories加载配置类,条件注解如@ConditionalOnClass是如何起作用的。在启动流程中,SpringApplication.run()中的各个步骤,比如prepareEnvironment、createApplicationContext、refreshContext等。 另外,可能需要提到一些设计模式,比如Spring Boot使用的工厂加载机制(Spring Factories Loader),以及事件驱动模型(Application Events),这些在启动过程中用于处理不同阶段的事件通知。 还需要注意用户的潜在问题,比如自动配置的覆盖和自定义配置的方法,或者启动过程中的扩展点。例如,如何通过排除某些自动配置类,或者使用@SpringBootApplication注解的exclude属性。启动流程中的ApplicationRunner和CommandLineRunner接口,可以在应用启动后执行自定义代码。 最后,要确保解释清晰,结构合理,先讲自动配置,再讲启动流程,每个部分分点说明,并给出源码示例或关键类和方法。避免过于深入细节,但又要覆盖主要的核心部分,帮助用户建立整体的理解框架。</think>Spring Boot 的自动配置和启动流程是其核心设计理念的体现,以下从源码层面对其核心机制进行拆解: ### 一、自动配置核心源码解析 **1. 触发入口** `@SpringBootApplication` 组合了 `@EnableAutoConfiguration`,其核心逻辑由 `AutoConfigurationImportSelector` 实现。该类通过 `selectImports()` 方法加载配置: ```java // AutoConfigurationImportSelector.java public String[] selectImports(AnnotationMetadata metadata) { List<String> configurations = getCandidateConfigurations(metadata, attributes); configurations = removeDuplicates(configurations); configurations = filter(configurations, autoConfigurationMetadata); return StringUtils.toStringArray(configurations); } ``` **2. 配置加载机制** 通过 `SpringFactoriesLoader` 加载 `META-INF/spring.factories` 文件中的预定义配置类: ```properties # spring-boot-autoconfigure-2.x.jar 中 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,... ``` **3. 条件化装配** 通过 `@Conditional` 系列注解实现智能装配,典型实现类: ```java // OnClassCondition 检查类路径是否存在目标类 class OnClassCondition extends FilteringSpringBootCondition { // 通过 ClassLoader 加载检查 } ``` **4. 配置优先级控制** 通过 `@AutoConfigureOrder` 和 `@AutoConfigureAfter` 控制配置类加载顺序 --- ### 二、启动流程源码解析 **1. 入口方法** `SpringApplication.run()` 方法核心流程: ```java public ConfigurableApplicationContext run(String... args) { // 1. 初始化监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); // 2. 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 3. 创建应用上下文(区分 Web/非Web 环境) context = createApplicationContext(); // 4. 刷新上下文(IoC 容器初始化核心) refreshContext(context); // 5. 执行 Runner 接口实现 callRunners(context, applicationArguments); } ``` **2. 上下文刷新关键** `AbstractApplicationContext.refresh()` 方法包含 12 个标准步骤,核心扩展点: ```java // SpringApplication.java 中的 refreshContext protected void refresh(ApplicationContext applicationContext) { ((AbstractApplicationContext) applicationContext).refresh(); } // 嵌入式容器启动在 onRefresh 阶段 protected void onRefresh() { createWebServer(); // 创建 Tomcat/Jetty 等实例 } ``` **3. 嵌入式容器启动** 以 Tomcat 为例: ```java // TomcatServletWebServerFactory.java public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); // 配置 Connector、Context 等组件 return new TomcatWebServer(tomcat); } ``` --- ### 三、关键设计模式 1. **工厂加载机制**:Spring Factories Loader 实现 SPI 扩展 2. **条件判断体系**:基于 ConditionEvaluator 的条件评估框架 3. **事件驱动模型**:通过 ApplicationEvent 实现启动过程状态广播 --- ### 四、调试建议 1. 在 `ConditionEvaluator#shouldSkip` 方法打断点,观察条件判断逻辑 2. 追踪 `ConfigurationClassParser#processConfigurationClass` 查看配置类解析过程 3. 监控 `SpringApplicationRunListeners` 各事件触发节点 理解这些源码需要结合具体场景分析,建议通过实际调试跟踪执行流程,同时参考官方文档中的自动配置报告(`--debug` 模式输出)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值