注:本文以spring-boot v3.4.1源码为基础,梳理spring-boot应用启动流程、分析自动装配的原理
如果对spring-boot2自动装配有兴趣,可以看看我另一篇文章:
Springboot2 自动装配之spring-autoconfigure-metadata.properties和spring.factories(SPI机制核心)
启动入口
以下是源码里一段应用启动单元测试代码:
package org.springframework.boot.test.autoconfigure;import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;import static org.assertj.core.api.Assertions.assertThat;/*** Tests for {@link ConditionReportApplicationContextFailureProcessor}.** @author Phillip Webb* @author Scott Frederick* @deprecated since 3.2.11 for removal in 3.6.0*/
@ExtendWith(OutputCaptureExtension.class)
@Deprecated(since = "3.2.11", forRemoval = true)
@SuppressWarnings("removal")
class ConditionReportApplicationContextFailureProcessorTests {@Testvoid loadFailureShouldPrintReport(CapturedOutput output) {SpringApplication application = new SpringApplication(TestConfig.class);application.setWebApplicationType(WebApplicationType.NONE);ConfigurableApplicationContext applicationContext = application.run();ConditionReportApplicationContextFailureProcessor processor = new ConditionReportApplicationContextFailureProcessor();processor.processLoadFailure(applicationContext, new IllegalStateException());assertThat(output).contains("CONDITIONS EVALUATION REPORT").contains("Positive matches").contains("Negative matches");}@Configuration(proxyBeanMethods = false)@ImportAutoConfiguration(JacksonAutoConfiguration.class)static class TestConfig {}
}
spring-boot3应用启动入口是SpringApplication的构造方法,这个构造方法里做了一些初始化,比较重要。如下:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");// @Athis.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// @Bthis.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());// @Cthis.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
@A:标签当前应用的启动主类,也就是我们平常写的xxxApplication类
@B:在类路径下查找是否有 :
- private static final String WEBMVC_INDICATOR_CLASS = “org.springframework.web.servlet.DispatcherServlet”;
- private static final String WEBFLUX_INDICATOR_CLASS = “org.springframework.web.reactive.DispatcherHandler”;
- private static final String JERSEY_INDICATOR_CLASS = “org.glassfish.jersey.servlet.ServletContainer”;
中的一个,标记当前web应用类型;web应用类型有:REACTIVE SERVLET NONE
@C:从类路径中可见的 spring.factories 文件中获取配置的BootstrapRegistryInitializer.class、ApplicationContextInitializer.class、ApplicationListener.class并缓存
todo~~