SpringBoot 是如何实现 main 方法启动 Web 项目的?核心原理是什么?
熊猫
传统Web项目启动过程,首选需要将Web项目打包成War包,然后通过Tomcat服务或则其它容器服务进行运行。
1.传统Web项目启动过程
传统Web项目启动过程,首选需要将Web项目打包成War包,然后通过Tomcat服务或则其它容器服务进行运行。
2.SpringBoot启动Web项目流程
SpringBoot是将Tomcat或其它容器服务作为依赖导入,通过java的main方法启动整个应用服务,包括Web容器。
3.SpringBoot启动过程详解
以下就是最简单的SpringBoot项目启动的入口
@SpringBootApplication
public class AdminMain {
public static void main(String[] args) {
SpringApplication.run(AdminMain.class,args);
}
}
1.初始化与准备
当执行SpringApplication.run()方法后,会创建一个SpringApplication对象
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
下面的代码是SpringApplication()的构造器,会执行以下内容:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 是否将命令行参数添加到 `Environment` 中作为属性源。默认启用,表示命令行参数会被解析进 `Spring Environment`
this.addCommandLineProperties = true;
// 用于在配置绑定或属性注入时自动转换类型(如字符串转枚举、数字等)。
this.addConversionService = true;
// 表示应用在没有显示器、键盘、鼠标的环境(如服务器)中运行;
this.headless = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
/**
设置应用上下文工厂(ApplicationContext 的创建方式)。
决定使用哪种 ApplicationContext:
AnnotationConfigServletWebServerApplicationContext(Web)
ReactiveWebServerApplicationContext
AnnotationConfigApplicationContext(非Web)
DEFAULT 会根据类路径自动推断(见后续 `deduceFromClasspath`)。
*/
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.properties = new ApplicationProperties();
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 初始化
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
构造器中大致做了以下事情:
- 推断应用类型(是否为 Web 应用),这是重点
- 设置初始化器(Initializers)
- 设置监听器(Listeners)
- 推断并设置 main 方法所在类,这是重点
以下是SpringApplication中run()方法代码
public ConfigurableApplicationContext run(String... args) {
Startup startup = SpringApplication.Startup.create();
if (this.properties.isRegisterShutdownHook()) {
shutdownHook.enableShutdownHookAddition();
}
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
startup.started();
if (this.properties.isLogStartupInfo()) {
(new StartupInfoLogger(this.mainApplicationClass, environment)).logStarted(this.getApplicationLog(), startup);
}
listeners.started(context, startup.timeTakenToStarted());
this.callRunners(context, applicationArguments);
} catch (Throwable ex) {
throw this.handleRunFailure(context, ex, listeners);
}
try {
if (context.isRunning()) {
listeners.ready(context, startup.ready());
}
return context;
} catch (Throwable ex) {
throw this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
}
}
run()方法大致做了以下事情:
- 创建并启动计时器
- 获取环境变量参数
- 准备上下文(预处理、加载属性源、应用初始化器等)
- 刷新上下文(这是关键步骤,会实例化所有单例 Bean),重要
- 执行 Runner(实现 CommandLineRunner 或 ApplicationRunner 的 Bean)
4.自动配置机制
SpringBoot最核心的部分是自动配置。它通过@EnableAutoConfiguration 注解(包含在@SpringBootApplication 中)启用。这个注解会导入AutoConfigurationImportSelector,它利用 Spring 的 SPI 机制从 classpath 下的META-INF/spring.factories 文件中读取自动配置类列表。每个自动配置类都用@ConditionalOnXXX 注解进行条件化配置,只有在满足特定条件(如某个类存在、某个 Bean 定义存在或某个属性设置)时才会应用该配置。
总结
谈到SpringBoot最重要的就是以下两点: 1.自动配置 如何实现自动装配的,重点就是SpringApplication注解内部的EnableAutoConfiguration注解,该注解会导入AutoConfigurationImportSelector,然后寻找classpath 下的META-INF/spring.factories 文件,并且读取自动配置类列表,根据@ConditionalOnXXX注解条件性导入。
2.SpringApplication构造器以及run方法干了那些 构造器:判断服务类型(是不是Web服务),推断主方法所在类,设置监听器、设置初始化器 run方法:读取配置信息,准备上下文和刷新上下文(会实例化所有单例 Bean)