tomcat源码解析---web项目在tomcat中的启动过程分析_tomcat解析web项目-程序员宅基地

技术标签: Tomcat源码  web项目启动流程  源码解读  

平常开发中只需要把开发好的war包上传到服务器,启动服务器,web项目就跟着启动运行了,这是为什么?服务器都做了哪些事情?下面我们通过跟踪调试tomcat源码,分析一下web项目的启动过程。
源码下载地址:
http://mirrors.hust.edu.cn/apache/tomcat/tomcat-8/v8.5.34/src/apache-tomcat-8.5.34-src.zip
下载完成解压后删除webapps目录下的examples目录,不删除启动可能会报错(我的机器上是这样的),然后在根目录下创建pom.xml的maven依赖文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.linxdcn</groupId>
    <artifactId>Tomcat8.0</artifactId>
    <name>Tomcat8</name>
    <version>8.0</version>
    <build>
        <finalName>Tomcat8</finalName>
        <sourceDirectory>java</sourceDirectory>
        <resources>
            <resource>
                <directory>java</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant-apache-log4j</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant-commons-logging</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.rpc</groupId>
            <artifactId>javax.xml.rpc-api</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.4</version>
        </dependency>
    </dependencies>
</project>

把文件保存好之后,就可以导入源码到开发工具中查看了。
查看源码之前,首先我们看一下tomcat的结构模型
在这里插入图片描述

  1. Server:代表整个服务器,一个服务器中可以有多个Service;
  2. Service: 由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求;
  3. Connector: 一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户;
  4. Engine:Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名
    当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理,Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理
  5. Host: 代表一个Virtual Host,虚拟主机,每个虚拟主机和某个网络域名Domain Name相匹配,每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理,匹配的方法是“最长匹配”,所以一个path==”"的Context将成为该Host的默认Context,所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配
  6. Context:一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成,Context在创建的时候将根据配置文件CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类,当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回

在源码中与这6个组件对应的类如下:
Connector :org.apache.catalina.connector.Connector.java
Server: org.apache.catalina.core.StandardServer.java
Service: org.apache.catalina.core.StandardService.java
Engine: org.apache.catalina.core.StandardEngine.java
Host: org.apache.catalina.core.StandardHost.java
Context: org.apache.catalina.core.StandardContext.java

组件的生命周期:Connector、StandardServer、StandardService、StandardEngine、StandardHost、StandardContext这6个组件类通过继承它们的父类都间接实现了生命周期接口Lifecycle。该接口定义组件在初始化、启动、停止、销毁的时候所要做的处理。初始化调用接口的init()方法,启动调用接口的start()方法,停止调用接口的stop()方法,销毁调用接口的destroy()方法。调用这些方法的前后通常会伴随着组件状态(LifecycleState)的改变,当组件状态改变的时候会发布相应的事件(LifecycleEvent),该事件将由接口注册的事件监听器(LifecycleListener)来处理。
Lifecycle接口部分内容:
在这里插入图片描述
源码跟踪:
tomcat启动入口在Bootstrap类下的main()函数
源码中的类路径:org.apache.catalina.startup.Bootstrap.java
main函数如下(代码过长的以后只列出核心代码)
在这里插入图片描述
进入Bootstrap的init()方法:
在这里插入图片描述
init()方法的核心是创建Catalina类的一个实例catalinaDaemon,回到main()函数中接着往下走
在这里插入图片描述
进入Bootstrap的load()方法:
在这里插入图片描述
在daemon.load(args)方法中反射调用了catalinaDaemon.load(args)方法,进入Catalina.load()方法中
在这里插入图片描述
digester这个对象中定义了在接下来的启动过程中要创建的对象以及创建对象的规则
file是读取conf/server.xml生成的文件
在这里插入图片描述
在这里插入图片描述
在Catalina.load()方法中接着往下走:
在这里插入图片描述
调用digester.parse()之后,在之前我们在createStartDigester()函数中添加的对象都会按照给定的规则实例化。
(Connector、StandardServer、StandardService、StandardEngine、StandardHost就是在这一步实例化的,StandardContext的实例化不在这个过程中,后面讲)
创建的过程参见Digester.startElement()方法和Rule.begin()方法。

在Catalina.load()方法中接着往下走:
在这里插入图片描述
getServer().init()执行的是StandardServer.init(),StandardServer中的init()方法来自于它父类的父类LifecycleBase,该类是一个实现生命周期接口Lifecycle的抽象类,LifecycleBase.init()方法的实现如下:
在这里插入图片描述
StandardServer的初始化主要是在StandardServer.initInternal()中完成的,其他几个组件跟这类似,初始化也是主要在自己的initInternal()方法中完成。

进入到StandardServer.initInternal()
在这里插入图片描述
在这里插入图片描述
StandardServer.initInternal()最后用循环调用StandardService.init()方法。init()方法的执行流程都是类似的,不再进入查看了。StandardService的初始化方法中又调用了StandardEngine的初始化方法。StandardEngine初始化完成后,整个的初始化过程完成(StandardHost和StandardContext的初始化不在这个过程中)。
getServer.init()方法执行完,load()方法执行完之后,接着执行Bootstrap的start()方法
在这里插入图片描述
进入Bootstrap的start()方法中:
在这里插入图片描述
Bootstrap.start()方法中反射调用了Catalina.start()方法,进入该方法中:
在这里插入图片描述
getServer().start()执行的是StandardServer.start()方法,与StandardServer.init()类似,StandardServer.start()最终执行的是StandardServer.startInternal()方法,进入该方法:
在这里插入图片描述
StandardService.start()最终执行的是 StandardService.startInternal()方法,进入该方法:
在这里插入图片描述
StandardEngine、StandardHost、StandardContext都继承了ContainerBase类,ContainerBase实现了容器接口Container。StandardHost是StandardEngine的子容器(child),StandardContext是StandardHost的子容器。
StandardEngine.start()方法最终调用的是ContainerBase.startInternal(),进入该方法中:
在这里插入图片描述
该方法的核心是自己启动的同时找到自己的子容器,并以多线程的方式启动它们。StandardEngine启动之后,会接着启动自己的子容器StandardHost。

StandardHost在启动的时候会发布一个启动事件给自己的监听器来处理,StandardHost的事件监听器的实现类是HostConfig,进入它的事件处理函数:
在这里插入图片描述
进入start()方法:
在这里插入图片描述
deployApps()就是部署Host中项目的操作,进入该函数:
在这里插入图片描述
这个函数就是根据不同的情况来部署我们的项目的,其中deployWARs()就是用来部署war包的,进入该函数:
在这里插入图片描述
该函数的核心是利用多线程来部署每一个war包,最总的部署代码是HostConfig.deployWAR(),进入该方法中:
在这里插入图片描述
在这里插入图片描述
该方法的核心是创建StandardContext的实例(每部署一个项目都会生成一个StandardContext的实例),并将其作为子容器添加到StandardHost中。StandardHost启动完成后启动它的子容器StandardContext。进入StandardContext.startInternal()方法中:
在这里插入图片描述
在该方法执行过程中发布了一个事件,进入StandardContext的事件监听器ContextConfig的事件处理函数中查看对该事件的处理:
在这里插入图片描述
进入configureStart()函数:
在这里插入图片描述
进入webConfig()函数:
在这里插入图片描述
这个函数的核心是对我们项目中web.xml文件的解析处理,在这个函数中接着往下走:
在这里插入图片描述
进入configureContext()中:
对
在这里插入图片描述
从web.xml中解析出Filter、Listener、Servlet定义的代码。
从web.xml中解析的所有内容都会添加到对应项目的StandardContext实例中。解析完成之后继续回到
StandardContext.startInternal()中往下执行:
在这里插入图片描述
如果我们的项目全部是基于注解开发的,没有web.xml文件,这一步的作用十分重要,想要了解的请去看
org.springframework.web.SpringServletContainerInitializer.class这个类。如果我们的项目是基于xml配置开发的
这一步貌似没什么卵用。接着往下执行:
在这里插入图片描述
进入listenerStart()函数:
在这里插入图片描述
listener是我们在web.xml中配置的,用于加载spring配置文件的,有兴趣的可以去看下源码contextInitialized()的实现,常见配置如下:
在这里插入图片描述
listener.contextInitialized()执行之后,我们web项目中的spring容器才真正启动。
回到StandardContext.startInternal()中往下执行:
在这里插入图片描述
loadOnStartup()方法的作用是初始化servlet,我们知道servlet有个init()方法,这个地方就是调用init()方法。
DispatcherServlet就是在这儿初始化的,它父类的初始化方法如下,有兴趣的可以去看下完整的初始化过程:
在这里插入图片描述

当StandardContext.start()执行完成之后,一个项目的基本启动流程算是执行完了。
分析的不是很细,建议大家下载源码自己跟一下启动过程。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_21441857/article/details/82992320

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan