1 springApplication的run
  run方法主要是用于创造spring容器ConfigurableApplicationContext对象。

public ConfigurableApplicationContext run(String... args) {
  StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察器
  stopWatch.start(); // 开始执行,记录开始时间
  ConfigurableApplicationContext context = null;
  configureHeadlessProperty();
  // 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
  SpringApplicationRunListeners listeners = getRunListeners(args);
  // 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
  // 这里接受ApplicationStartedEvent事件的listener会执行相应的操作
  listeners.started();
  try {
  // 构造一个应用程序参数持有类
  ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

  //创建并配置环境

  ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
  //输出banner

Banner printedBanner = printBanner(environment);
  context = createApplicationContext();
  analyzers = new FailureAnalyzers(context);
  prepareContext(context, environment, listeners, applicationArguments,printedBanner);
  refreshContext(context);
  afterRefresh(context, applicationArguments);
  listeners.finished(context, null);
  stopWatch.stop();
  if (this.logStartupInfo) {
  new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  }
  return context;

  }
  catch (Throwable ex) {
  handleRunFailure(context, listeners, ex); // 这个过程报错的话会执行一些异常操作、然后广播出ApplicationFailedEvent事件给相应的监听器执行
  throw new IllegalStateException(ex);
  }
}

2 run的过程

按顺序看run,发现执行了下面这些过程。

(1 )stopWatch 记录开始结束时间,configureHeadlessProperty 设置headless模式,awt的headless,一般运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能。

(2)springApplicationListeners: 这个类包含了SpringApplicationRunlistener的集合和一个日志类。SpringApplicationRunlistener也是通过spring.factories加载,如下可以看到,就包含一种EventPublishingRunListener。
  org.springframework.boot.SpringApplicationRunListener=\
  org.springframework.boot.context.event.EventPublishingRunListener
  EventPublishingRunListener通过看源码,发现包含了started environmentPrepared contextPrepared contextLoaded等方法,基本都是包装特定event并发event。配合run函数的代码如下,可以得知,springApplicationListeners主要负责在run函数的各个阶段,发起事件。比如在创建spring容器的前后调用了start和finish方法,在创建容器时,把listener当参数传入便于在各个时间发起事件。

(3)prepareEnvironment  创建并设置环境

  private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {
  // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    if (isWebEnvironment(environment) && !this.webEnvironment) {
      environment = convertToStandardEnvironment(environment);
    }
    return environment;
  }

如上,设置环境分几个步骤,getOrderCreateEnvironment获得一个标准环境对象StandardEnvironment,然后configureEnvironment进行配置。其中configureEnvironment 包含两个配置,configurePropertySources和configureProfiles两个方法。Environment代表程序运行环境,包含两种信息,一个是profiles,描述各种bean defination,另一种是properties描述系统配置,包括配置文件 jvm属性文件 环境变量等。configureEnvironment方法先是调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles。然后listener发出事件。

(4)pringBnner 打印banner,打印banner信息,即启动时出现的logo信息。

(5)createApplicationContext  创建spring容器。如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器,否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器

(6)prepareContext    首先调用了postProcessApplicationContext(context),如果是web程序并且是spring web容器,那么设置实例命名生成器并注册,同时注册资源加载器并注册。然后调用applyInitializers(context),遍历每个初始化器,调用相应的innitialize方法让初始化器开始工作。

(7)refreshContext(context) 刷新spring容器,内部做很多事情,包括springFactory设置,BeanFactoryPostProcessor接口执行,BeanPostProcessor接口执行,自动化配置类解析,条件注解解析,国际化的初始化等。

(8)afterRefresh  调用了 callRunners,主要是得到所有的CommonandLineRunner和ApplicationRunner, 使用 @Order(value=x)设置排序值,可以支持自定义runner完成自己需求。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
  List<Object> runners = new ArrayList<Object>();
  // 找出Spring容器中ApplicationRunner接口的实现类
  runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  // 找出Spring容器中CommandLineRunner接口的实现类
  runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  // 对runners进行排序
  AnnotationAwareOrderComparator.sort(runners);
  // 遍历runners依次执行
      for (Object runner : new LinkedHashSet<Object>(runners)) {
    if (runner instanceof ApplicationRunner) { // 如果是ApplicationRunner,进行ApplicationRunner的run方法调用
      callRunner((ApplicationRunner) runner, args);
    }
  if (runner instanceof CommandLineRunner) { // 如果是CommandLineRunner,进行CommandLineRunner的run方法调用
      callRunner((CommandLineRunner) runner, args);
    }
  }
}

springboot启动过程(2)-run方法的更多相关文章

  1. SpringBoot启动过程原理

    最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理. 一.springboot的三种启动方式: 1.运行带有main方法的2.通过命令 Java -jar命令3 ...

  2. Spring Boot 学习笔记一(SpringBoot启动过程)

    SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...

  3. (四)SpringBoot启动过程的分析-预处理ApplicationContext

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(三)SpringBoot启动过程的分析-创建应用程序上下文,本文将分析上下文创建完毕之后的下一步操作:预处理上下文容器. 预处理上下文 ...

  4. (一)SpringBoot启动过程的分析-启动流程概览

    -- 以下内容均基于2.1.8.RELEASE版本 通过粗粒度的分析SpringBoot启动过程中执行的主要操作,可以很容易划分它的大流程,每个流程只关注重要操作为后续深入学习建立一个大纲. 官方示例 ...

  5. (五)SpringBoot启动过程的分析-刷新ApplicationContext

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇[(四)SpringBoot启动过程的分析-预处理ApplicationContext] (https://www.cnblogs.co ...

  6. (三)SpringBoot启动过程的分析-创建应用程序上下文

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创 ...

  7. springboot启动过程(3)-refresh方法

    1  springboot在启动的时候,会调用run方法,创建环境设置spring容器,其中包含refresh方法,完成配置类解析,各种beanFactoryPostProcess和beanPostP ...

  8. springboot启动过程(1)-初始化

    1   springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication. ...

  9. SpringBoot启动过程原理(转)

    1.1 Springboot启动: @SpringBootApplication public class ServerApplication { public static void main(St ...

随机推荐

  1. 使用PathfindingProject Pro 4.0.10实现2D自动寻路

    昨天由于策划的要求,要在项目的最后加个自动寻路的功能,跑去研究了下自动寻路的插件.不多说,上操作 首先在寻路的游戏物体上加上seeker.AI Lerp这两个脚本,注意要给target赋值. 之后给目 ...

  2. 解决CentOS 6环境时区、日期、时间同步方法

    有些时候我们在选择的VPS服务商提供的VPS主机方案安装系统.安装建站环境之后就直接上马网站,但是我们会有发现发布的文章或者有些时候设置的自动执行脚本时间与我们实际的时间不符合.甚至有些程序是需要与本 ...

  3. asp.net中异步调用webservice

    WebService方法是不需要作任何修改的,只是在调用时采用异步的方式,这样在循环中,速度会显得快一点. 原来的方式: HotelMagWeb.com.china_sms.www.MainServi ...

  4. Deep Learning(Ian Goodfellow) — Chapter1 Introduction

    Deep Learning是大神Ian GoodFellow, Yoshua Bengio 和 Aaron Courville合著的深度学习的武功秘籍,涵盖深度学习各个领域,从基础到前沿研究.因为封面 ...

  5. 去掉标题栏的方法(使用requestWindowFeature(Window.FEATURE_NO_TITLE);为什么失效?不仅失效,可能会挂)

    使用requestWindowFeature(Window.FEATURE_NO_TITLE)隐藏标题栏失效的原因,不仅失效,可能会挂.可能是activity继承的是AppCompatActivity ...

  6. Handsontable 的数据保存(增删改查+导出excel)

    项目用到handsontable 插件 根据官网 API写的handsontable初始化, 数据展示, ajax请求, 参数封装, Controller参数接受 全局容器 var AllData = ...

  7. Spring_总结_04_高级配置(一)_Profile

    一.前言 本文承接上一节:Spring_总结_03_装配Bean(四)之导入与混合配置 这一节,来总结一下profile. 我们在开发软件时,通常会进行跨环境部署.而在跨环境部署时,经常会遇到某些环境 ...

  8. LeetCode OJ:Triangle(三角形)

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  9. c++引用和指针的实现

    引用和指针有什么区别?引用在进程中是否会分配内存? C++ primer中说: 引用就是对象的另一个名字. C++ primer中说: 指针用于指向对象,保存的是另一个对象的地址. 从字面意义上,感觉 ...

  10. MSSQL Join的使用

    假设我们有下面两张表.表A在左边,表B在右边.我们给它们各四条记录. id name id name -- ---- -- ---- 1 Pirate 1 Rutabaga 2 Monkey 2 Pi ...