1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch(); //设置计时器
  3. stopWatch.start(); //记录当前时间
  4. ConfigurableApplicationContext context = null;
  5. configureHeadlessProperty(); //设置java.awt.headless为true或false
  6. SpringApplicationRunListeners listeners = getRunListeners(args);//获取事件发布器(控制所有事件的执行时机)
  7. listeners.started(); //事件发布器发布ApplicationStartedEvent事件,所有监听了该事件的ApplicationListener实现类执行逻辑
  8. try {
  9. context = doRun(listeners, args);
  10. stopWatch.stop(); //计时结束(记录总共花了多少时间)
  11. if (this.logStartupInfo) {
  12. new StartupInfoLogger(this.mainApplicationClass)
  13. .logStarted(getApplicationLog(), stopWatch);
  14. }
  15. return context;
  16. }
  17. catch (Throwable ex) {
  18. handleRunFailure(context, listeners, ex);
  19. throw new IllegalStateException(ex);
  20. }
  21. }
  1. private ConfigurableApplicationContext doRun(SpringApplicationRunListeners listeners,
  2. String... args) {
  3. ConfigurableApplicationContext context;
  4. // Create and configure the environment
  5. ConfigurableEnvironment environment = getOrCreateEnvironment(); //创建Environment
  6. configureEnvironment(environment, args); //配置Environment(包括配置要使用的PropertySource和Profile)
  7. listeners.environmentPrepared(environment); //事件发布器发布ApplicationEnvironmentPreparedEvent事件,所有监听了该事件的ApplicationListener执行相应逻辑
  8. if (isWebEnvironment(environment) && !this.webEnvironment) {
  9. environment = convertToStandardEnvironment(environment);
  10. }
  11.  
  12. if (this.bannerMode != Banner.Mode.OFF) {
  13. printBanner(environment);
  14. }
  15.  
  16. // Create, load, refresh and run the ApplicationContext
  17. context = createApplicationContext(); //创建ApplicationContext容器
  18. context.setEnvironment(environment); //设置Environment到容器
  19. postProcessApplicationContext(context);
  20. applyInitializers(context); //执行所有的ApplicationContextInitializer的initial方法,对创建出来的ApplicationContext容器进行初始化
  21. listeners.contextPrepared(context);
  22. if (this.logStartupInfo) {
  23. logStartupInfo(context.getParent() == null);
  24. logStartupProfileInfo(context);
  25. }
  26.  
  27. // Add boot specific singleton beans
  28. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  29. context.getBeanFactory().registerSingleton("springApplicationArguments",
  30. applicationArguments);
  31.  
  32. // Load the sources
  33. Set<Object> sources = getSources();
  34. Assert.notEmpty(sources, "Sources must not be empty");
  35. load(context, sources.toArray(new Object[sources.size()])); //将之前通过@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加载到已经准备完毕的ApplicationContext
  36. listeners.contextLoaded(context); //事件发布器将所有的ApplicationListener注册给当前的ApplicationContext,之后发布ApplicationPreparedEvent事件
  37.  
  38. // Refresh the context
  39. refresh(context); //刷新ApplicationContext
  40. if (this.registerShutdownHook) {
  41. try {
  42. context.registerShutdownHook();
  43. }
  44. catch (AccessControlException ex) {
  45. // Not allowed in some environments.
  46. }
  47. }
  48. afterRefresh(context, applicationArguments);
  49. listeners.finished(context, null);
  50. return context;
  51. }

步骤总结:

  • 设置计时器,记录当前时间

    • 该类是一个非线程的安全的,如果自己使用要考虑多线程的情况.
  • 设置java.awt.headless为true或false
    • java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true
  • 获取事件发布器(用于控制所有事件的执行时机)
  • 事件发布器发布ApplicationStartedEvent事件,所有监听了该事件的ApplicationListener实现类执行逻辑
  • 创建并配置Environment(包括配置要使用的PropertySource和Profile)
    • PropertySource主要是读取SpringApplication.setDefaultProperties指定的默认属性 + 命令行属性

      • 通常,只有命令行属性,而且该属性会addFirst,说明优先级是最高的!!!
    • Profile主要是读取application-{level}.properties中的内容
      • 需要配置:"spring.active.profiles"
    • 关于配置文件的一系列问题 附 5 springboot之配置文件
  • 事件发布器发布ApplicationEnvironmentPreparedEvent事件,所有监听了该事件的ApplicationListener执行相应逻辑
  • 创建ApplicationContext容器
  • 设置Environment到容器
  • 执行所有的ApplicationContextInitializer的initial方法,对创建出来的ApplicationContext容器进行初始化
  • 将之前通过@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加载到已经准备完毕的ApplicationContext
    • 装载beanDefinition到ApplicationContext(之后在使用Bean的时候,直接由beanDefinition初始化为bean)
  • 事件发布器将所有的ApplicationListener注册给当前的ApplicationContext,之后发布ApplicationPreparedEvent事件
  • 刷新ApplicationContext
    • 这里如果有ContextRefreshedEvent的监听器,那么此时就会触发其onApplication方法
  • 结束计时,记录整个启动时间

以上红色部分就是核心步骤!

参考:

http://www.jianshu.com/p/692b10aef052

http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow

《springboot揭秘-快速构建微服务体系》

【附4】springboot源码解析-run()的更多相关文章

  1. 附4 springboot源码解析-run()

    public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); / ...

  2. 附3 springboot源码解析 - 构建SpringApplication

    package com.microservice.framework; import org.springframework.boot.SpringApplication; import org.sp ...

  3. SpringBoot源码解析系列文章汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的SpringBoot源码解析系列文章的汇总,当你使用SpringBoot不仅仅满足于基本使用时.或者出去面试被面试官虐了时.或者说想要深入了解一下 ...

  4. springboot源码解析-管中窥豹系列之总体结构(一)

    一.简介 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  5. springboot源码解析-管中窥豹系列之项目类型(二)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  6. springboot源码解析-管中窥豹系列之Runner(三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  7. springboot源码解析-管中窥豹系列之Initializer(四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  8. springboot源码解析-管中窥豹系列之aware(六)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  9. springboot源码解析-管中窥豹系列之web服务器(七)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

随机推荐

  1. 位运算求最值 学习笔记 (待补充QAQ)

    没有什么前言?直接进入正题qwq 俩俩异或 求最值: 建trie树 O(n)枚举每个数找这个数的最值,每次反走就成,还可以剪枝一波(如果在某位已经小于ans显然可以直接return? void Ins ...

  2. table 的td 自适应事项

    media的html结构,如果用display:table-cell实现, table { width: 100%; border-collapse: collapse; border: $bor; ...

  3. LINUX中的ACL

    一. 为什么要使用ACL先让我们来简单地复习一下Linux的文件权限. 在 linux下,对一个文件(或者资源)可以进行操作的对象被分为三类: file owner(文件 的拥有者),group(组, ...

  4. Python高阶函数(Map、Reduce、Filter)

    Map函数 map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回. 举例说明 比如我们有一个函数f(x)=x2,要把这个函数作用 ...

  5. jmeter之Java request报错:java.lang.NoClassDefFoundError: redis/clients/jedis/Jedis

    今天在学习Jmeter的java request,请求内容是连接redis并获取其中的一个字段值.结果在运行时报如下错误: 2018/05/24 13:08:20 ERROR - jmeter.thr ...

  6. iOS常用第三方类库及Xcode插件

    第三方类库(github地址): 1.AFNetworking 网络数据     https://github.com/AFNetworking/AFNetworking 2.SDWebImage 图 ...

  7. Air Jordan 1 Los Primeros Will be unveiled

    This new pair of Air Jordan 1 Los Primeros is part of the popular Air-Jordan- Line signature and is ...

  8. Django初级手册2-管理界面的使用及定制

    管理界面的使用 管理界面的URL,帐号和密码在第一次输入syncdb时建立 http://127.0.0.1:8000/admin/ 将app加入管理界面 编辑polls/admin.py from ...

  9. eclipse设置字体、字符编码、快捷键

    1.设置字体: preferences->general->appearnce->colors and fonts->edit->字体大小14,字形常规,字体Consol ...

  10. 错误:Python Urlfetch Error:'GET

    1) 如果你初装了 GaAgent, 记得把在 proxy.ini 里的 id 填上:2) 刷新几次:3) 把浏览器关了,重新打开:4) 清除浏览器的缓冲区:5) 清除 cookies6) 用浏览器的 ...