深入剖析Tomcat原理

本文详细介绍了如何在IntelliJIDEA中部署和运行Tomcat源码,包括创建新工程、配置pom.xml、设置运行参数等步骤,并解决了启动时可能出现的问题。同时,文章探讨了HTTP工作流程和DNS解析的基本过程,以及Tomcat的整体架构,包括连接器Coyote和容器的角色。最后,概述了Tomcat的启动流程和源码调试方法。
摘要由CSDN通过智能技术生成

深入剖析Tomcat原理

一、 Tomcat源码部署和运行(intellij IDEA)
1、下载tomcat源码,以tomcat-8为例
链接: https://tomcat.apache.org/
在这里插入图片描述
在这里插入图片描述
2、源码部署到IDEA中

①创建新的空工程
在这里插入图片描述
②解压源码压缩包到该工程的目录(目录名最好是非中文和非空格组成的)下
在这里插入图片描述
③创建home文件,并将webapps和conf文件移入home文件中,目的是为了后期配置IDEA运行时参数时方便
在这里插入图片描述
④新建pom.xml文件,在其中添加tomcat运行时依赖:
在这里插入图片描述

<?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>org.apache.tomcat</groupId>
    <artifactId>apache‐tomcat‐8.5.42‐src</artifactId>
    <name>Tomcat8.5</name>
    <version>8.5</version>
 
    <build>
        <finalName>Tomcat8.5</finalName>
        <sourceDirectory>java</sourceDirectory>
        <!-- <testSourceDirectory>test</testSourceDirectory>-->
        <resources>
            <resource>
                <directory>java</directory>
            </resource>
        </resources>
        <!--<testResources>
           <testResource>
                <directory>test</directory>
           </testResource>
        </testResources>-->
        <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>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxrpc</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.5.1</version>
        </dependency>
       
    </dependencies>
</project>

⑤在这个空project项目新建maven项目:
在这里插入图片描述
⑥新建完maven项目后,添加application(用来启动/调试这些源码)
在这里插入图片描述
在这里插入图片描述
找到**java/org.apache/catalina/startup/bootstrap(类)**点击完成添加(主要是这个类就是整个tomcat启动的类,其中包含main()方法)
这时有可能添加错误,因为没有导入jdk
在这里插入图片描述
⑦不报错后设置运行时参数:
在这里插入图片描述
在这里插入图片描述
就是选择刚刚新建的home目录路径
参数:
-Dcatalina.home=C:/Users/14047/IdeaProjects/tomcat-src/apache-tomcat-8.5.42-src/home
-Dcatalina.base=C:/Users/14047/IdeaProjects/tomcat-src/apache-tomcat-8.5.42-src/home
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=C:/Users/14047/IdeaProjects/tomcat-src/apache-tomcat-8.5.42-src/home/conf/logging.properties
注意

⑧以上设置无误后则可以启动
在这里插入图片描述
⑨浏览器访问Tomcat会出现问题:
在这里插入图片描述
原因:
在这里插入图片描述
解决:
搜索并找到这个ContextConfig类下的configureStart()方法
在这里插入图片描述
在该方法中的webConfig()方法下添加:
context.addServletContainerInitializer(new JasperInitializer(), null)
目的是手动将JSP解析器初始化
在这里插入图片描述
重新启动Tomcat问题解决
在这里插入图片描述
二、不得不提的HTTP工作流程与DNS解析详细过程

HTTP工作流程与DNS解析详解.

三、Tomcat整体架构

1)Http服务器的执行逻辑的两种方法:
1、Http服务器接收请求,根据请求先做一个判断,找到对应的业务类执行具体业务逻辑,这种方法耦合度过高(不推荐)
在这里插入图片描述
2、Http服务器不亲自调用业务类,而是直接把请求转发给tomcat,由tomcat去判断需要调用具体哪个类来执行业务操作。
显然第二种方法解耦合度比较好。
在这里插入图片描述
2)连接器+容器
Tomcat整体包含两大组件:连接器+容器 = service
这两大组件分别与之对应的是http服务器、servlet容器

1、 连接器:主要负责客户端浏览器传过来的请求+初始化request和response
2、 容器主要负责处理某个具体servlet的调用逻辑

浏览器发出请求----->连接器首先接收请求,构建request对象,在request对象构建中解析请求信息,封装相关属性(url、method…)。----->连接器将构建好的request对象传递给容器处理------->容器拿到request,根据request对象中的信息定位到哪个具体的servlet,并初始化且调用该servlet执行具体逻辑------>容器在调用某个servlet前已经将response对象构建好了,servlet执行完具体业务逻辑后,response对象中会包含响应数据,容器再将包含响应数据的response对象再响应回给连接器。------>连接器解析完response后再响应给浏览器

四、Tomcat整体架构——连接器(Coyote)与容器初讲
在这里插入图片描述
连接器在tomcat中称为coyote
Coyote主要负责底层socket连接的接收与响应,接收到浏览器的请求后,构建并封装进request对象,最终再转换成servletRequest对象传递给容器
将协议的处理、io的相关等操作交给coyote,将具体业务逻辑的操作等交给容器
一个service可以有多个连接器coyote和一个容器,但它们都不能单独对外提供服务,两者结合为service后,一个service才能对外提供服务。

一个service至少包含一个连接器和容器。
通过service接口就可看出其对应关系
向Service中添加Connector,可以是数组(add……)
在这里插入图片描述
给service设置一个容器只能是一个(set……)
在这里插入图片描述
连接器组件coyote的内部细节

1)连接器组件coyote的内部细节:

在这里插入图片描述
一个连接器中包含了四个组件:EndPoint、Processor、Adapter、ProtocolHandler
客户端浏览器发送请求至EndPoint(通信端点(专门用来接收发送过来的socket请求)),
EndPoint处理完后将请求又发送给处理器Processor,Processor将请求按照HTTP协议格式进行解析,拆封并封装成request对象。
对容器来说它只支持servletRequest规范,而对Processor来说它只提供Request,这时就需要用到适配器组件,将Request转换为servletRequest。

2)service中容器和连接器的整体地位
在这里插入图片描述
从源码中也能看出来,是一一对应的,一个service中有很多组件,核心就是容器在这里插入图片描述
catalina:这个包包含启动项、容器、连接器(整体)、公共类等
coyote:这个包包含连接器(connector)下的各个组件(protocolHandler、adapter、processor等)

3)service内部细节
在这里插入图片描述
Contain(容器)具体结构详解:
在这里插入图片描述
Engine(引擎):管理多个虚拟站点(虚拟主机),也是一个service只能有一个引擎。一个引擎可管理多个Host。一个Host可包含多个Context(项目),一个Context下包含多个Wrapper(servlet)

通过server.xml就可以看出其中的层次关系与上描述相符
在这里插入图片描述
通过源码分析看出
容器中包含着这四个组件
在这里插入图片描述
五、Tomcat源码基础上深入分析启动流程
Tomcat启动时序图:
在这里插入图片描述
1、用户点击startup.bat即可启动tomcat
在这里插入图片描述
Startup.bat文件中的具体细节:
在这里插入图片描述
其中调用了catalina.bat这个文件
在这里插入图片描述
catalina.bat这个文件中又调用了bootStrap类中的main()方法来开启整个tomcat的启动
在这里插入图片描述
六、上手Debug 源码跟踪Tomcat各个步骤

明确tomcat入口点为BootStrap类中的main()方法:
Startup.bat—>Catalina.bat---->Bootstrap.main()
1、Application让Bootstrap.main()方法启动,此方法一启动Bootstrap类的静态属性先初始化
在这里插入图片描述
在这里插入图片描述
//获取到home文件目录
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
2、初始化完静态变量后来到main()方法体:
构建BootStrap,给非静态属性赋初值null
在这里插入图片描述
在这里插入图片描述
3、bootstrap.init()方法执行,初始化Bootstrap
在这里插入图片描述
①初始化类加载器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
② 反射创建Catalina(容器)组件
在这里插入图片描述
Catalina组件的配置是依靠配置文件(server.xml)
在这里插入图片描述
最后init()方法结束,Catalina组件成功构建
在这里插入图片描述
初始化完成之后继续往下走:

③ 调用load方法:
匹配命令参数(“start”)
在这里插入图片描述
bootstrap调用load()方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从以上可以看出:BootStrap的load()方法主要功能就是去调用Catalina组件的load方法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述Server.xml配置文件解析的相关设置完成,返回digester
在这里插入图片描述
在这里插入图片描述
Parse这一步是核心,因为这里在解析server.xml配置文件的同时时已将server接口的一个实现类创建出来(standardServer),并依据配置文件中的值,给standardServer的各个属性设置好相应的值,其中就包括services数组等
Parse前:
在这里插入图片描述
Parse后:
在这里插入图片描述

services(Server)中只有一个名为Server01的service
server.xml
在这里插入图片描述
这些组件在这一步只是依照server配置文件的配置项被构建出来,但组件中的一些必须的初始化还是要等到后续的init()方法完成。

④ 创建完Server后开始进行初始化init()
在这里插入图片描述
这里getServer()拿到Server,实现Server接口的是standardServer类
在这里插入图片描述
在这里插入图片描述
Server.init()根据多态,调用standardServer的init方法,standardServer无init()方法,根据继承默认调用父类 LifecycleMBeanBase的init()方法,发现LifecycleMBeanBase也无此方法
在这里插入图片描述
,则又去默认调用父类LifecycleBase的init()方法,诶发现有
在这里插入图片描述
则执行init()方法中的具体逻辑(this=standardServer,this.super.super.init()),其中又有initInternal()方法执行,此方法为抽象方法,standardServer中已实现,this.super.super.initInternal()调用时传的是this也就是standardServer,所以又跑回去执行standardServer中initInternal()方法具体逻辑
initInternal()方法中核心点就是对services数组中的每一个service进行初始化:
在这里插入图片描述
*(LifecycleMBeanBase类实现了LifeCycle接口,并抽取且提供了一些相同的代码功能,standardServer继承此类,重写相应方法,其它配置直接调用父类方法即可(模板思想)。)

⑤ 初始化每个service时同样利用多态思想,与server的初始化大致相同
在这里插入图片描述
This.super.super.init()方法初始化,其中initInternal()传递this,调用standardService的
在这里插入图片描述
引擎等都属于容器范畴,所以又多继承了一层containerBase
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
也就是:this.super.super.super.init(),同样的其中initInternal()还是回到StrandardEngine类中
在这里插入图片描述
引擎(Engine)初始化完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值