SpringBoot启动流程总结
1.导语
//以下是一个SpringBoot应用的标准入口: public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } //SpringApplication.run 内部是这样的:先创建一个 SpringApplication 对象,然后调用他的run方法。 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
所以想要了解清楚 SpringBoot 启动流程,相当于了解 SpringApplication 的 构造方法 和 run方法。
2.构造方法详解
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 判断应用类型,会有三种情况: // NONE:非web应用 // SERVLET:普通web应用 // REACTIVE:响应式web应用 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 从 META-INF/spring.factories 文件中获取如下内容 // 获取 注册初始化器:在 run 方法中的 createBootstrapContext(); 里会被使用 this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // 获取 容器初始化器:在 run 方法中的 prepareContext( ... ); 里会被使用 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 获取 监听器:在 run 方法中 listeners.xxx 时被使用 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
3.run方法详解
public ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); // 第一步:创建监听器 SpringApplicationRunListeners listeners = getRunListeners(args); // 发布事件:开始启动 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 第二步:准备环境变量 // 把一系列设置整合成 environment,包括 系统变量、JVM参数、启动参数(args)、配置文件(application、bootstrap等) ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); Banner printedBanner = printBanner(environment); // 第三步:创建空容器 // 根据 new 时判断的 web类型(webApplicationType),创建对应类型的容器 context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 第四步:准备容器 // 把前面准备的东西注入进去,包括 环境变量(environment)、事件监听器(listeners)、启动参数(applicationArguments) prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 第五步:启用容器 // 解析@SpringBootApplication注解,加载自动配置类 // 进行Bean的扫描、加载、实例化、依赖注入 // 如果是Web应用,会启动一个内嵌式的Web服务器比如Tomcat refreshContext(context); // 容器初始化后的操作,是个空方法,要使用需要继承并重写 afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } // 发布事件:已启动 listeners.started(context, timeTakenToStartup); // 执行启动后的自定方法: // 实现 ApplicationRunner、CommandLineRunner 接口 callRunners(context, applicationArguments); } catch (Throwable ex) { if (ex instanceof AbandonedRunException) { throw ex; } handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { // 检查应用是否还在运行 if (context.isRunning()) { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); // 发布事件:准备就绪 listeners.ready(context, timeTakenToReady); } } catch (Throwable ex) { if (ex instanceof AbandonedRunException) { throw ex; } handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } // 返回Bean容器 return context; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步