深入springboot怎么启动tomcat
深入springboot怎么启动tomcat
- @EnableAutoConfiguration做了哪些事
- 小总结
- Tomcat何时启动的呢?
- 小总结
这是中高级工程师面试中常问的问题。
知道现在有多卷了吧!
我记得我刚找工作那会儿,我只要8000的工资,面试官都要问这个问题。我真TM的醉了!
关于SpringBoot自动配置流程请看:深入Springboot启动流程+自动配置原理.
如果你对基本的启动原理有大致的了解,那么可以继续阅读此篇文章。否则请先阅读深入Springboot启动流程+自动配置原理.。
@EnableAutoConfiguration做了哪些事
我们知道,因为@EnableAutoConfiguration
注解的存在,SpringBoot项目启动的时候,会去找到依赖包中META-INF/spring.factories文件,将文件中的自动配置类找出来,加载进内存!
那么和Tomcat相关的配置类,也存在于spring.factories之中:
我们发现这里配置了一个类: ServletWebServerFactoryAutoConfiguration。
这个类是干嘛用的呢?
点进去一看!
不看不知道,一看吓一尿:
根据上图的标识我们分三步来解释:
@ConditionalOnWebApplication
( type = Type.SERVLET):条件判断,如果当前的项目的类型为Servlet我才继续运行当前的ServletWebServerFactoryAutoConfiguration配置类,这里判断通过。@EnableConfigurationProperties
({ServerProperties.class}),这个注解我在深入Springboot启动流程+自动配置原理.中有解释。那么呢,这里呢,就是去绑定我们application.properties中关于server的参数!
例如:
指定我们服务的端口、地址等。在SpringBoot启动的时候就会被从application.properties中读取到当前的ServletWebServerFactoryAutoConfiguration配置类中,进行web服务的初始化!@Import
(EmbeddedTomcat.class、 EmbeddedJetty.class): 这是什么? Tomcat?Jetty?并且通过@Import
注解注入容器了!聪明的朋友猜到了,Tomcat/Jetty服务就是在这里进行初始化的。
好!由于我们这里研究的是TomCat,我们点进EmbeddedTomcat看看!
可以看到EmbeddedTomcat是一个由@Configuration
修饰的静态内部配置类,向容器中注入了一个名叫TomcatServletWebServerFactory的对象(重点,后面会用到这个对象)。
这个时候有同学就有疑问了,在ServletWebServerFactoryAutoConfiguration类中通过@Import
导入了三个对象:
- EmbeddedTomcat
- EmbeddedJetty
- EmbeddedUndertow
那这里为什么只加载了EmbeddedTomcat呢? 因为我们的@ConditionalOnClass
条件注解,我们的依赖中没有Jetty和Undertow相关的类,因此EmbeddedJetty和EmbeddedUndertow不会加载。只会加载EmbeddedTomcat!
所以现在呢,重点来到了TomcatServletWebServerFactory这个对象上,我们进去看看。
我们发现通过new TomcatServletWebServerFactory(); 创建了一个TomcatServletWebServerFactory对象,然后构造方法设置了一系列参数。这里我们直接跳过,去看这个类中最重要的一个方法:getWebServer()
这个方法我们后面会做解释,划重点!!!!!
小总结
那么@EnableAutoConfiguration
对于Tomcat的工作现在就做完了,做了什么事情呢?
向Spring容器中注入了一个初始化后,名叫TomcatServletWebServerFactory的对象。该对象继承自ServletWebServerFactory接口(记住)。我们现在可以认为TomCat服务准备好了,等待启动。那什么时候启动的呢?
Tomcat何时启动的呢?
这个时候就要回到我们的启动类上了:
这个SpringApplication.run()方法我们之前一直没有系统介绍过,这里我简单介绍一下。
首先我们点进run方法
发现首先创建了一个SpringApplication对象。
然后继续调用到了一个同名的run方法头上。
好!
重点就是这个run方法了,它做了什么事情呢?
我这里借鉴一下百度百科上面的解释:
public ConfigurableApplicationContext run(String... args) {//记录程序运行时间StopWatch stopWatch = new StopWatch();stopWatch.start();// ConfigurableApplicationContext Spring 的上下文ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();//【1、获取并启动监听器】SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//【2、构造应用上下文环境】ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//处理需要忽略的BeanconfigureIgnoreBeanInfo(environment);//打印bannerBanner printedBanner = printBanner(environment);///【3、初始化应用上下文】context = createApplicationContext();//实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//【4、刷新应用上下文前的准备阶段】prepareContext(context, environment, listeners, applicationArguments, printedBanner);//【5、刷新应用上下文】refreshContext(context);//【6、刷新应用上下文后的扩展接口】afterRefresh(context, applicationArguments);//时间记录停止stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//发布容器启动完成事件listeners.started(context);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;}
- 获取并启动监听器 通过加载META-INF/spring.factories 完成了 SpringApplicationRunListener实例化工作(告诉相关人员,SpringBoot要启动了,你们把自己该初始化的初始化了)
- 构造容器环境,简而言之就是加载系统变量,环境变量,配置文件
- 创建容器
- 实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
- 准备容器
- 刷新容器 :refreshContext(context)
- 刷新容器后的扩展接口
由于我们这里专门讨论TomCat的启动,所以我们其他的就不多去研究,直接找到最重要的地方:
第6步:刷新容器 ,这一步是整个SpringBoot非常重要的一步,IOC等等核心都是通过这一步来实现的。
我们进入refreshContext()方法看看:
好,继续点:
继续:
发现是一个接口,我们看有那些实现类:
哇,有那么多实现类,到底调用的是哪个呢?
java多态的知识来了
这个时候我们去看看,这个方法是谁调用的?
是一个叫ConfigurableApplicationContext的类调用的,那么继续去寻找,我们就会发现:
我们要找的实现类是这个!
点进去!
代码很长,我们直接去到onRefresh() 方法。
点进去:
妈的,继续找实现类:
找到和web相关的实现类进去一看:
来了来了
就是这个方法:
- 获取到容器中已经存在的ServletWebServerFactory对象(是不是有点熟悉?回到第一节结尾处去看看!),然后调用了什么方法?
调用了什么方法????
是不是getWebServer()!!
我们看看ServletWebServerFactory的子类(由于我这里的按理项目有两个Spring版本,不管它,正常情况下面的实现类,一种只有一个):
其中是不是有TomcatServletWebServerFactory?
而这个TomcatServletWebServerFactory是不是在@EnableAutoConfiguration
环节创建好的???
好!!! 现在程序拿到了我们的TomcatServletWebServerFactory,并调用了其中的getWebServer()方法!!!!
好了,最终的决战来了。
getWebServer()方法到底做了什么??
我们到目前为止还没看到TomCat启动的任何蛛丝马迹,getWebServer()方法是我们最后的救命稻草了。
好!开始:
- 创建了一个Tomcat对象,然后一系列赋值。
- 调用了一个叫getTomcatWebServer()的方法。最终返回一个WebServer对象
继续:
new了一个TomcatWebServer对象(WebServer的子类),我们去看看它的构造方法:
一顿非空判断加赋值,最后调用到了initialize()方法。 看到这个名字就知道,这是什么?
初始化
Tomcat启动了。
小总结
在 SpringApplication.run()中,刷新容器的时候,程序会去找到在@EnableAutoConfiguration
阶段创建好的ServletWebServerFactory,它的实现类可能是TomCat可能是Jetty,根据我们项目所引入的依赖自动实例化。
最后由ServletWebServerFactory调用getWebServer()方法启动web容器。
深入springboot怎么启动tomcat相关推荐
- SpringBoot内置tomcat启动原理
前言 不得不说SpringBoot的开发者是在为大众程序猿谋福利,把大家都惯成了懒汉,xml不配置了,连tomcat也懒的配置了,典型的一键启动系统,那么tomcat在springboot是怎么启动的 ...
- Springboot内嵌tomcat
Springboot内嵌tomcat 前言 一.依赖引入starter-web 二.源码截图 tomcat 如何内嵌 三.springboot 如何启动tomcat 前言 一.依赖引入starter- ...
- SpringBoot中的Tomcat是如何启动的
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-bo ...
- tomcat start 无法启动_解密Springboot内嵌Tomcat
Springboot简介 相信大多数开发者对Springboot比较熟悉了,它能够快速地创建一个spring应用,能够完全摒弃XML的配置方式,并且内嵌了Tomcat.Jetty这样的Servlet容 ...
- SpringBoot内置Tomcat启动不了的原因
SpringBoot内置Tomcat启动不了的原因: 1.需要加入spring-boot-starter-web依赖 [web中集成了tomcat.dispatcherServlet.xml-] &l ...
- springboot内嵌Tomcat启动失败
问题描述 开发需求期间引入友军的二方包,导致服务启动失败,失败日志如下 java.lang.reflect.InvocationTargetExceptionat sun.reflect.Native ...
- SpringBoot启动Tomcat原理与嵌入式Tomcat实践
导读 作为一个开发,使用Spring Boot 时,和传统的Tomcat 部署相比,我们只需要关注业务的开发,项目的启动和部署变的十分简单, 那么它背后是怎么实现的, 隐藏着什么? 本文先从一个嵌入式 ...
- idea springboot配置外置tomcat好处
idea springboot配置外置tomcat好处: 1.原先用内置的tomcat,改动一点点java代码,热部署时会自动重启(可以重控制台中重到)---------慢 2.原先用内置的tomca ...
- SpringBoot内置tomcat出现error:An incompatible version [1.1.32] of the APR based Apache Tomcat Native lib
SpringBoot内置tomcat出现error:An incompatible version [1.1.32] of the APR based Apache Tomcat Native lib ...
最新文章
- Android开发实践:在任意目录执行NDK编译
- python电脑下载网址-python下载文件文件到本地电脑(基于requests)
- 【spring-boot】restfull api 返回值中,去掉 null 值
- 18岁初中毕业学Java_刚满十八 初中毕业 java自学完了 没学历 该怎么办?
- (原创总结) Quartus II 的在线调试方法
- HDOJ---2546 饭卡[DP01背包问题]
- php验证码只有图片没有文字_有没有免费好用的图片文字识别工具?在线就能使用超准确...
- launchpad乐器_PreSonus 发布 ATOM 打击垫控制器(视频)
- Canvas实例之鼠标移动特效(彩色小球)
- Migration——迁移
- 美国3D理发师可剪出球星脸发型
- 湖北科目三驾考经验总结
- unity如何插入图片_unity 图片导入及其使用方法
- spring tx:advice 和 aop:config 配置事务 1
- Beta冲刺总结随笔
- java毕业设计车牌信息管理系统Mybatis+系统+数据库+调试部署
- requests使用splash
- Opencv 分水岭算法 watershed的图像分割
- 抖音开发者工具配置抖音小游戏为横屏显示的方法
- 汉字转拼音的使用手册
热门文章
- TCP 糊涂窗口综合症(silly window syndrome)与 rate-based 流控
- 个人的生活经历和实习经历
- caffe与卷积神经网络
- QUICK PCB抄板教程(无网络编号)
- 【转】Voip 知识
- starting tomcat v7.0 server at localhost has encountered a problem错误解法方法
- [Swift]LeetCode60. 第k个排列 | Permutation Sequence
- 宏观调控绝不是微观控制
- 在线检查英文语法神器
- 免外围电路ESP32/ESP8266系列单片机串口一键下载方案