北京网站开发多少钱,wordpress积分提现,登封网站制作,企业网站的制作方式《Spring Boot 源码学习系列》 SpringApplication 的 run 方法核心流程介绍 一、引言二、往期内容三、主要内容3.1 run 方法源码初识3.2 引导上下文 BootstrapContext3.3 系统属性【java.awt.headless】3.4 早期启动阶段3.5 准备和配置应用环境3.6 打印 Banner 信息3.7 新建应用…《Spring Boot 源码学习系列》 SpringApplication 的 run 方法核心流程介绍 一、引言二、往期内容三、主要内容3.1 run 方法源码初识3.2 引导上下文 BootstrapContext3.3 系统属性【java.awt.headless】3.4 早期启动阶段3.5 准备和配置应用环境3.6 打印 Banner 信息3.7 新建应用上下文3.8 准备和配置应用上下文3.9 刷新应用上下文3.10 afterRefresh 方法3.11 打印启动日志3.12 Spring 容器启动完成3.13 callRunners 方法3.14 Spring 容器正在运行中3.15 异常处理 四、总结 一、引言 
在前面的博文《初识 SpringApplication》中Huazie 带大家一起分析了 SpringApplication 类实例化的逻辑。当 SpringApplication 对象被创建之后我们就可以调用它的 run 方法来启动和运行 Spring Boot 项目。 
本篇博文将围绕 SpringApplication 的 run 方法展开带大家一起从源码分析 Spring Boot 的运行流程。 二、往期内容 
在开始本篇的内容介绍之前我们先来看看往期的系列文章【有需要的朋友欢迎关注系列专栏】 Spring Boot 源码学习  Spring Boot 项目介绍  Spring Boot 核心运行原理介绍  【Spring Boot 源码学习】EnableAutoConfiguration 注解  【Spring Boot 源码学习】SpringBootApplication 注解  【Spring Boot 源码学习】走近 AutoConfigurationImportSelector  【Spring Boot 源码学习】自动装配流程源码解析上  【Spring Boot 源码学习】自动装配流程源码解析下  【Spring Boot 源码学习】深入 FilteringSpringBootCondition  【Spring Boot 源码学习】OnClassCondition 详解  【Spring Boot 源码学习】OnBeanCondition 详解  【Spring Boot 源码学习】OnWebApplicationCondition 详解  【Spring Boot 源码学习】Conditional 条件注解  【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解  【Spring Boot 源码学习】RedisAutoConfiguration 详解  【Spring Boot 源码学习】JedisConnectionConfiguration 详解  【Spring Boot 源码学习】初识 SpringApplication  【Spring Boot 源码学习】Banner 信息打印流程  【Spring Boot 源码学习】自定义 Banner 信息打印  【Spring Boot 源码学习】BootstrapRegistryInitializer 详解  【Spring Boot 源码学习】ApplicationContextInitializer 详解  【Spring Boot 源码学习】ApplicationListener 详解  【Spring Boot 源码学习】SpringApplication 的定制化介绍  【Spring Boot 源码学习】BootstrapRegistry 详解  【Spring Boot 源码学习】深入 BootstrapContext 及其默认实现  【Spring Boot 源码学习】BootstrapRegistry 初始化器实现  【Spring Boot 源码学习】BootstrapContext的实际使用场景  【Spring Boot 源码学习】深入 ApplicationContext 初始化器实现  【Spring Boot 源码学习】共享 MetadataReaderFactory 上下文初始化器  【Spring Boot 源码学习】ConditionEvaluationReport 日志记录上下文初始化器  
三、主要内容 注意 以下涉及 Spring Boot 源码 均来自版本 2.7.9其他版本有所出入可自行查看源码。 3.1 run 方法源码初识 上述截图就是 SpringApplication 的 run 方法核心代码。 
下面 Huazie 将带着大家一起通读这块源码从整体上了解下 run 方法核心流程。 
3.2 引导上下文 BootstrapContext 
DefaultBootstrapContext bootstrapContext  createBootstrapContext();翻看 DefaultBootstrapContext 的源码可知从 Spring Boot 2.4.0 版本开始支持引导上下文。 在《BootstrapRegistryInitializer 详解》中Huazie 带大家详细分析了加载并初始化 BootstrapRegistryInitializer 的逻辑。而这里的 createBootstrapContext 方法就是用于创建默认的引导上下文对象 DefaultBootstrapContext并利用 BootstrapRegistry 初始化器初始化该引导上下文对象。 
想深入了解的朋友们可查看 Huazie 下面列出的博文 
《BootstrapRegistry 详解》《深入 BootstrapContext 及其默认实现》《BootstrapRegistry 初始化器实现》《BootstrapContext的实际使用场景》 
3.3 系统属性【java.awt.headless】 
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS  java.awt.headless;// 配置 java.awt.headless 系统属性
private void configureHeadlessProperty() {System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}java.awt.headless 是 Java 中的一个系统属性用于指示 Java 应用程序是否运行在 Headless 模式下。Headless 模式是指系统缺少显示设备、键盘或鼠标的状态通常应用于服务器环境如应用集群、数据库集群等这些环境通常通过网络远程操作没有实际的显示设备。 
在 Java 中AWTAbstract Window Toolkit 是用于构建图形用户界面GUI应用的标准 API 接口。 
Java 为 AWT 提供了两种模式实现以适应不同的运行环境 
标准模式适用于具有可用显示设备、驱动和图形用户界面的环境。Headless 模式 适用于没有显示设备、驱动或图形用户界面的环境例如服务器。 注意 设置 java.awt.headless 属性为 true 会使 Java AWT 工具包在 headless 模式下运行这意味着它将不会尝试加载或访问与图形用户界面相关的资源或功能。 3.4 早期启动阶段 
SpringApplicationRunListeners listeners  getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);SpringApplicationRunListeners 中包含了一组 SpringApplicationRunListener 的集合。SpringApplicationRunListener 是 SpringApplication 的 run 方法的监听器它用来监听 Spring Boot 应用的不同启动阶段这些阶段都会发布对应的事件。 
这里 starting 方法就对应了最早期的启动阶段它在 run 方法刚开始执行时就被立即调用。starting 方法里会发布 ApplicationStartingEvent 事件通过监听该事件应用可以执行一些非常早期的初始化工作比如配置系统属性、初始化基础组件等等。 
3.5 准备和配置应用环境 
ApplicationArguments applicationArguments  new DefaultApplicationArguments(args);
ConfigurableEnvironment environment  prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);ApplicationArguments 是 Spring Boot 中用于获取命令行参数的接口其默认实现是 DefaultApplicationArguments。 
prepareEnvironment 方法用于准备和配置应用程序的运行时环境它会发布 ApplicationEnvironmentPreparedEvent 事件通过监听该事件应用程序可以执行一系列操作来准备和配置其运行环境。其返回的 ConfigurableEnvironment 对象包含了应用程序的所有配置信息。 
通过 ConfigurableEnvironment 对象我们可以获取特定配置属性的值也可以在运行时动态修改配置属性。 
我们来看看 configureIgnoreBeanInfo 方法 在 configureIgnoreBeanInfo 方法中可以看到如下代码 
Boolean ignore  environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,Boolean.class, Boolean.TRUE);从上述代码中可以看到通过 environment 变量获取属性名为 spring.beaninfo.ignore 的属性值其 getProperty 方法有三个参数 
第一个参数是属性名。第二个参数是期望返回的属性值的类型这里是 Boolean.class。第三个参数是默认值如果找不到属性或者属性不能被转换为 Boolean 类型则使用 Boolean.TRUE 作为默认值。 
系统属性 spring.beaninfo.ignore 用于指示 Spring 在调用 JavaBeans Introspector 时使用Introspector.IGNORE_ALL_BEANINFO 模式。如果此属性的值为 true则 Spring 会跳过搜索 BeanInfo 类通常适用于以下情况应用程序中的 beans 从一开始就没有定义这样的类。 
默认值是 false表示 Spring 会考虑所有的 BeanInfo 元数据类就像标准 Introspector.getBeanInfo(Class) 调用那样。如果在启动时或延迟加载时反复访问不存在的 BeanInfo 类开销很大可以考虑将此标志切换为 true。 
请注意如果存在反复访问不存在的 BeanInfo 类可能也表明缓存未奏效。最好将 Spring 的 jar 包与应用类放在同一个 ClassLoader 中这样可以在任何情况下与应用程序的生命周期一起进行干净的缓存。对于 Web 应用程序如果采用多 ClassLoader 布局可以考虑在 web.xml 中声明一个本地的 org.springframework.web.util.IntrospectorCleanupListener这也可以实现有效的缓存。 
3.6 打印 Banner 信息 
Banner printedBanner  printBanner(environment);printBanner 方法用于 Spring Boot 启动时的 Banner 信息打印。 
想要深入了解 Banner 打印的读者们请查看如下博文 
《Banner 信息打印流程》《自定义 Banner 信息打印》 
3.7 新建应用上下文 
ConfigurableApplicationContext context  createApplicationContext();protected ConfigurableApplicationContext createApplicationContext() {return this.applicationContextFactory.create(this.webApplicationType);
}上述 createApplicationContext 方法的功能是根据给定的 Web 应用程序类型 webApplicationType 创建一个可配置的应用上下文对象 ConfigurableApplicationContext 。 
在《初识 SpringApplication》这篇博文的 2.2 小节【Web 应用类型推断】中大家可以看到 Web 应用程序类型 webApplicationType 是如何获取的这里不赘述了感兴趣的可以自行查看。 
3.8 准备和配置应用上下文 
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);setApplicationStartup 方法用于设置当前应用上下文的 ApplicationStartup 这允许应用上下文在启动期间记录指标。 
prepareContext 方法用于准备和配置应用程序上下文这里会依次发布如下事件 
ApplicationContextInitializedEvent当 SpringApplication 启动并且 ApplicationContext 已准备好且 ApplicationContextInitializer 集合已被调用但在加载任何 bean 定义之前将发布该事件。ApplicationPreparedEvent 当 SpringApplication 启动并且 ApplicationContext 已经完全准备好但尚未刷新时将发布事件。在此阶段bean 定义将被加载环境已经准备好可以使用。 
3.9 刷新应用上下文 
static final SpringApplicationShutdownHook shutdownHook  new SpringApplicationShutdownHook();refreshContext(context);private void refreshContext(ConfigurableApplicationContext context) {if (this.registerShutdownHook) {shutdownHook.registerApplicationContext(context);}refresh(context);
}protected void refresh(ConfigurableApplicationContext applicationContext) {applicationContext.refresh();
}registerShutdownHook 变量表示是否应注册一个关闭钩子默认为 true。 
SpringApplicationShutdownHook 是一个用于执行 Spring Boot 应用程序优雅关闭的 Runnable 关机钩子。这个钩子跟踪已注册的应用程序上下文以及通过 SpringApplication.getShutdownHandlers() 注册的任何操作。 
refreshContext 方法里面可以看到调用 refresh 方法refresh 方法里面则是调用 ConfigurableApplicationContext【实现类是 AbstractApplicationContext 该类属于 spring-context 包】的 refresh 方法该方法是用来刷新底层的应用上下文。 
它会加载或刷新配置的持久化表示这可能来自基于 Java 的配置、XML 文件、属性文件、关系数据库模式或其他某种格式。调用此方法后要么实例化所有单例对象要么不实例化任何单例对象。 
它最后会发布 ContextRefreshedEvent 事件通过监听该事件可以执行一些应用上下文初始化或刷新后需要进行的操作。 
3.10 afterRefresh 方法 
刷新应用上下文之后调用 afterRefresh 方法。该方法的实现默认为空可由开发人员自行扩展。 3.11 打印启动日志 
long startTime  System.nanoTime();Duration timeTakenToStartup  Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}System.nanoTime() 用于获取当前时间的纳秒值。 
Duration.ofNanos() 用于将纳秒数转换为 Duration 对象timeTakenToStartup 表示 Spring Boot 应用启动所需的时间。 
logStartupInfo 表示是否需要记录启动信息如果为 true则需要记录启动信息。 
StartupInfoLogger 类用于在应用程序启动时记录应用信息其中 logStarted 方法用于以 INFO 日志级别打印应用启动时间。 实际运行日志信息类似如下 3.12 Spring 容器启动完成 
listeners.started(context, timeTakenToStartup);这里表示上下文已经刷新应用程序已经启动但是 CommandLineRunners 和 ApplicationRunners 尚未被调用。 
SpringApplicationRunListeners 的 started 方法里会发布 ApplicationStartedEvent 事件通知监听器 Spring 容器启动完成。 
3.13 callRunners 方法 
callRunners(context, applicationArguments);callRunners 方法里面会调用 ApplicationRunner 和 CommandLineRunner 的运行方法。 通过阅读上述代码可以总结如下 
首先从 context 中获取类型为 ApplicationRunner 和 CommandLineRunner 的 Bean接着将它们放入 List 列表中并进行排序。最后再遍历排序后的 ApplicationRunner 和 CommandLineRunner 的 Bean并调用它们的 run 方法。 
Spring Boot 提供 ApplicationRunner 和 CommandLineRunner 这两种接口是为了通过它们来实现在容器启动时执行一些操作。在同一个应用上下文中可以定义多个 ApplicationRunner 或 CommandLineRunner 的bean并可以使用 Ordered 接口或 Order 注解进行排序。 
ApplicationRunner 和 CommandLineRunner 这两个接口都有一个 run 方法但不同之处是 
ApplicationRunner 中 run 方法的参数为 ApplicationArgumentsCommandLineRunner 中 run 方法的参数为 字符串数组 
如果需要访问 ApplicationArguments 而不是原始的字符串数组大家可以考虑使用 ApplicationRunner。 
3.14 Spring 容器正在运行中 
Duration timeTakenToReady  Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);这里表示应用上下文已经刷新所有的 CommandLineRunners 和 ApplicationRunners 都已被调用应用程序已准备好处理请求。 
SpringApplicationRunListeners 的 ready 方法里会发布 ApplicationReadyEvent 事件通知监听器 Spring 容器正在运行中。 
在 Spring Boot 2.6.0 版本之前大家看到调用的是 SpringApplicationRunListener 的 running 方法。从 Spring Boot 2.6.0 版本开始新增了 ready 方法替代 running 方法。在 Spring Boot 3.0.0 版本中正式去除 running 方法。 3.15 异常处理 
handleRunFailure(context, ex, listeners);从 3.5 到 3.13 小节 如果出现异常则会捕获后调用 handleRunFailure 进行异常处理。 
3.14 小节同样它如果出现异常也会捕获后调用 handleRunFailure 进行异常处理。 
handleRunFailure 方法里会发布 ApplicationFailedEvent 事件通过监听该事件开发人员可以实现如下的一些操作 
错误日志记录当应用启动失败时可以记录详细的错误信息到日志文件中便于后续的问题排查和分析。通知发送在应用启动失败时可以发送通知给相关的开发或运维人员以便他们能够及时响应并处理问题。数据备份如果应用在启动过程中出现异常可能需要对某些关键数据进行备份以防止数据丢失。资源清理在应用启动失败的情况下可能需要释放或清理已经分配的资源如数据库连接、文件句柄等。尝试自动恢复在某些情况下可以尝试自动重启应用或者执行其他恢复操作以减少人工干预的需求。自定义处理逻辑根据具体的业务需求实现自定义的错误处理逻辑比如回滚事务、关闭网络连接等。 
有关这块更详细的内容后续 Huazie 将专门出一篇讲解敬请期待 
四、总结 
本篇 Huazie 向大家初步介绍了 SpringApplication 的 run 方法核心流程。由于篇幅受限其中很多环节并未深入讲解后续 Huazie 将会针对这些内容深入分析和大家一起从源码详细了解 Spring Boot 的运行流程。