博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringApplication执行流程
阅读量:2168 次
发布时间:2019-05-01

本文共 4293 字,大约阅读时间需要 14 分钟。

SpringApplication执行流程

SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下:

  1. 如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:
    根据classpath里面是否存在某个特征类org.springframework.web.context.ConfigurableWebApplicationContext来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
    使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer
    使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener
    推断并设置main方法的定义类。
public class SpringApplication {
// ... public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) {
this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = deduceWebApplicationType(); // 查找并加载所有可用的ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 查找并加载所有可用的ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }}
  1. SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。
  2. 创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。
  3. 遍历调用所有SpringApplicationRunListenerenvironmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。
  4. 如果SpringApplicationshowBanner属性被设置为true,则打印banner
  5. 根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
  6. ApplicationContext创建好之后,SpringApplication会再次借助SpringFactoriesLoader,查找并加载classpath中所有可用的ApplicationContextInitializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。
  7. 遍历调用所有SpringApplicationRunListenercontextPrepared()方法。
  8. 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。
  9. 遍历调用所有SpringApplicationRunListenercontextLoaded()方法。
  10. 调用ApplicationContextrefresh()方法,完成IoC容器可用的最后一道工序。
  11. 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
  12. 正常情况下,遍历执行SpringApplicationRunListenerfinished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理)

Spring 源码:

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection
exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); // SpringFactoriesLoader => META-INF/spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); // 环境配置 None(非WEB), Servlet, Reactive(响应式) ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); // Banner Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] {
ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); // IOC容器的最后一步 refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); // 查找 CommandLineRunner, ApplicationRunner, ... callRunners(context, applicationArguments); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
listeners.running(context); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

转载地址:http://lvxzb.baihongyu.com/

你可能感兴趣的文章
TensorFlow-11-策略网络
查看>>
浅谈 GBDT
查看>>
如何选择优化器 optimizer
查看>>
一文了解强化学习
查看>>
CART 分类与回归树
查看>>
seq2seq 的 keras 实现
查看>>
seq2seq 入门
查看>>
什么是 Dropout
查看>>
用 LSTM 做时间序列预测的一个小例子
查看>>
用 LSTM 来做一个分类小问题
查看>>
详解 LSTM
查看>>
按时间轴简述九大卷积神经网络
查看>>
详解循环神经网络(Recurrent Neural Network)
查看>>
为什么要用交叉验证
查看>>
用学习曲线 learning curve 来判别过拟合问题
查看>>
用验证曲线 validation curve 选择超参数
查看>>
用 Grid Search 对 SVM 进行调参
查看>>
用 Pipeline 将训练集参数重复应用到测试集
查看>>
PCA 的数学原理和可视化效果
查看>>
机器学习中常用评估指标汇总
查看>>