一、自动装配原理

  之前博文已经讲过,@SpringBootApplication继承了@EnableAutoConfiguration,该注解导入了AutoConfigurationImport Selector,这个类主要是扫描spring-boot-autoconfigure下面的META-INF\spring.factories中的EnableAutoConfiguration对应的全类名,其中XXXAutoConfiguration都是一个个自动配置类。

  自动装配原理具体参考:Spring Boot系列(二):Spring Boot自动装配原理解析

二、Spring Boot的jar启动

  1、Spring Boot自动装配Tomcat组件

  ① EmbeddedWebServerFactoryCustomizerAutoConfiguration内嵌的Web容器工厂定制器自动装配类,装配了TomcatWebServerFactoryCustomizer组件

  Tomcat工厂定制器TomcatWebServerFactoryCustomizer用来设置容器的属性,把ServerProperties中的属性设置到Tomcat容器的工厂中。

  ServerProperties服务的属性类:

  ② ServletWebServerFactoryAutoConfiguration,ServletWeb工厂自动装配类,装配了如下四个组件

  • ServletWebServerFactoryCustomizer:用来定制ServletWeb服务工厂
  • TomcatServletWebServerFactoryCustomizer:用来定制TomcatServletWeb服务工厂
  • ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar :后置处理器
  • ServletWebServerFactoryConfiguration:用来配置TomcatServletWeb服务工厂

  2、SpringApplication.run启动流程

  ① new SpringApplication(primarySources),创建了一个SpringApplication

  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. //设置主配置类 我们自己写的Spring Boot的启动类
  5. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  6. //设置web应用的类型
  7. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  8. //设置容器初始化器(ApplicationContextInitializer类型的)
  9. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  10. //把监听器设置到SpringApplication中[ApplicationListener]
  11. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  12. //设置主配置类
  13. this.mainApplicationClass = deduceMainApplicationClass();
  14. }

  ② SpringApplication的run方法:

  主要流程:

  第一:创建容器对象

  第二:去META-INFO/spring.factories中获取SpringApplicationRunListener监听器(事件发布监听器)

  第三:发布容器starting事件(通过spring的事件多播器)

  第四:封装命令行参数

  第五:准备容器环境

  第六:打印Springboot的图标

  第七:根据webApplicationType来创建容器

  第八:准备容器上下文

  第九:发布容器启动事件

  第十:发布容器运行事件

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. //容器对象
  5. ConfigurableApplicationContext context = null;
  6. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  7. configureHeadlessProperty();
  8. //去META-INFO/spring.factories中获取SpringApplicationRunListener监听器(事件发布监听器)
  9. SpringApplicationRunListeners listeners = getRunListeners(args);
  10. //发布容器starting事件(通过spring的事件多播器)
  11. listeners.starting();
  12. try {
  13. //封装命令行参数
  14. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  15. /**
  16. * 准备容器环境
  17. * 1: 获取或者创建环境
  18. * 2:把命令行参数设置到环境中
  19. * 3:通过监听器发布环境准备事件
  20. */
  21. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  22. configureIgnoreBeanInfo(environment);
  23. //打印Springboot的图标
  24. Banner printedBanner = printBanner(environment);
  25. //创建容器根据webApplicationType来创建容器(通过反射创建)
  26. context = createApplicationContext();
  27. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
  28. new Class[] { ConfigurableApplicationContext.class }, context);
  29. /**
  30. * 准备上下文
  31. * 1:把环境设置到容器中
  32. * 2: 循环调用ApplicationContextInitializer进行容器初始化工作
  33. * 3: 发布容器上下文准备完成事件
  34. * 4: 注册关于Springboot特性的相关单例Bean
  35. * 5: 发布容器上下文加载完毕事件
  36. */
  37. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  38. refreshContext(context);
  39. //运行ApplicationRunner和CommandLineRunner
  40. afterRefresh(context, applicationArguments);
  41. stopWatch.stop();
  42. if (this.logStartupInfo) {
  43. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  44. }
  45. //发布容器启动事件
  46. listeners.started(context);
  47. //运行ApplicationRunner和CommandLineRunner
  48. callRunners(context, applicationArguments);
  49. }
  50. catch (Throwable ex) {
  51. //出现异常调用异常分析保护类进行分析
  52. handleRunFailure(context, ex, exceptionReporters, listeners);
  53. throw new IllegalStateException(ex);
  54. }
  55.  
  56. try {
  57. //发布容器运行事件
  58. listeners.running(context);
  59. }
  60. catch (Throwable ex) {
  61. handleRunFailure(context, ex, exceptionReporters, null);
  62. throw new IllegalStateException(ex);
  63. }
  64. return context;
  65. }

  ③ org.springframework.boot.SpringApplication#refreshContext

  ④ org.springframework.boot.SpringApplication#refresh

  ⑤ org.springframework.context.support.AbstractApplicationContext#refresh

  到了AbstractApplicationContext#refresh方法,之前讲过Spring IoC源码解析讲过该方法的12大步,这里就不细说,详细可以参考:Spring系列(三):Spring IoC源码解析,里面说过有一步就是onRefresh(),这个方法默认是空的,由子类根据自身需要去实现

  ⑥ org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

  该onRefresh方法分2步

  第一:super.onRefresh(); 调用父类的onRefresh()

  第二:createWebServer();创建Web服务,很重要,很重要,很重要!!!

  ⑦ createWebServer()方法

  第一:ServletContext servletContext = getServletContext(); 获取Servlet的上下文

  第二:ServletWebServerFactory factory = getWebServerFactory();获取Tomcat的Web服务工厂

  第三:this.webServer = factory.getWebServer(getSelfInitializer()); 创建一个Web服务器

  ⑧ TomcatServletWebServerFactory#getWebServer()方法,主要用于创建一个Tomcat Web容器

  到此我们知道Spring Boot的启动通过Spring IoC的refresh中的的onRefresh()带动了Tomcat的启动,跟我们之前我们学Spring Mvc的时候刚好相反,Spring Mvc的是Tomcat的启动带动了Spring容器的启动;

三、普通Web工程启动

  1、普通的web工程,我们找到web.xml,会发现都配置了如下的加载Spring的配置。

  2、Tomcat启动的时候会调用该上下文加载的的监听器的contextInitialized方法,我们进入到该方法:

  3、进入初始化Web应用上下文initWebApplicationContext方法中:

  • this.context = createWebApplicationContext(servletContext);
  • configureAndRefreshWebApplicationContext(cwac, servletContext);

  4、进去到configureAndRefreshWebApplicationContext(cwac, servletContext)方法中:

  5、进入到refresh方法实际就到了org.springframework.context.support.AbstractApplicationContext#refresh的方法

  这个方法很熟悉了,Spring IoC的refresh的12大步;

四、Spring Boot启动流程图

Spring Boot系列(四):Spring Boot源码解析的更多相关文章

  1. spring MVC cors跨域实现源码解析

    # spring MVC cors跨域实现源码解析 > 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就 ...

  2. spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource

    spring MVC cors跨域实现源码解析 spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议 ...

  3. 老生常谈系列之Aop--Spring Aop源码解析(二)

    老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...

  4. 老生常谈系列之Aop--Spring Aop源码解析(一)

    老生常谈系列之Aop--Spring Aop源码解析(一) 前言 上一篇文章老生常谈系列之Aop--Spring Aop原理浅析大概阐述了动态代理的相关知识,并且最后的图给了一个Spring Aop实 ...

  5. 第十四章 Executors源码解析

    前边两章介绍了基础线程池ThreadPoolExecutor的使用方式.工作机理.参数详细介绍以及核心源码解析. 具体的介绍请参照: 第十二章 ThreadPoolExecutor使用与工作机理 第十 ...

  6. ThreadPoolExecutor系列<三、ThreadPoolExecutor 源码解析>

    本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.html 在源码解析前,需要先理清线程池控制的运行状态 ...

  7. 小学徒成长系列—StringBuilder & StringBuffer关键源码解析

    在前面的博文<小学徒成长系列—String关键源码解析>和<小学徒进阶系列—JVM对String的处理>中,我们讲到了关于String的常用方法以及JVM对字符串常量Strin ...

  8. Java 集合系列Stack详细介绍(源码解析)和使用示例

    Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现 ...

  9. Android进阶:四、RxJava2 源码解析 1

    本文适合使用过Rxjava2或者了解Rxjava2的基本用法的同学阅读 一.Rxjava是什么 Rxjava在GitHub 主页上的自我介绍是 "a library for composin ...

  10. 第四章 CopyOnWriteArraySet源码解析

    注:在看这篇文章之前,如果对CopyOnWriteArrayList底层不清楚的话,建议先去看看CopyOnWriteArrayList源码解析. http://www.cnblogs.com/jav ...

随机推荐

  1. CSMA/CD ,现在的交换式以太网还用吗?谈全双工,半双工与CSMA/CD的关系

    我们知道:以太网访问控制用的是CSMA/CD,即载波侦听多点接入/ 冲突检测,是以广播的方式将数据发送到所有端口: 我们还知道:交换机能主动学习端口所接设备的MAC地址,在获知该端口的MAC 地址后, ...

  2. circle踢人(约瑟夫环) c++

    这里更新指针法,真的每句都是坑 (寥寥数十句,句句都是坑) // // Created by snnnow on 2020/4/12. //question:转圈,一共N个人,数到M的出列,求最后一个 ...

  3. 02_Linux实操篇

    第五章 VI和VIM编辑器 5.1. VI和VIM基本介绍 Vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器.由于对Unix及Linux系统的任何版本,Vi ...

  4. pandas 几个重要知识点

    将 NaN 替换成某一数值 使用 fillna dataframe.fillna(value = 'xxx',inplace=True) 删除某一个值 使用 drop dataframe.drop(1 ...

  5. 11-Pandas之排序(df.sort_index()、df.sort_values()、随机重排、随机采样)

    排序是一种索引机制的一种常见的操作方法,也是Pandas重要的内置运算,主要包括以下3种方法: 排序方法 说明 sort_values() 根据某一列的值进行排序 sort_index() 根据索引进 ...

  6. PHP curl_share_close函数

    (PHP 5 >= 5.5.0) curl_share_close — 关闭 cURL 共享句柄 说明 void curl_share_close ( resource $sh ) 关闭 cUR ...

  7. 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分

    LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...

  8. luogu P3217 [HNOI2011]数矩形

    LINK:数矩形 题意:给出n个点 求出一个最大的矩形. 矩形可以使斜着的.(不会告诉你样例我算了几年 这道题的一个潜规则 矩形面积都是整数 我也不知道为啥一定是整数 姑且是题目输出的要求吧. 所以用 ...

  9. MySQL进阶篇(03):合理的使用索引结构和查询

    本文源码:GitHub·点这里 || GitEE·点这里 一.高性能索引 1.查询性能问题 在MySQL使用的过程中,所谓的性能问题,在大部分的场景下都是指查询的性能,导致查询缓慢的根本原因是数据量的 ...

  10. 15 张精美动图全面讲解 CORS

    前言: 本文翻译自 Lydia Hallie 小姐姐写的