1. 首页 > 快讯

征服 Tomcat:深入浅出指南

大家好,如果您还对征服 Tomcat:深入浅出指南不太了解,没有关系,今天就由本站为大家分享征服 Tomcat:深入浅出指南的知识,包括的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

[[432343]]

图片来自Pexels

大多数企业Web 应用程序都在其上运行。 Tomcat是程序员的老朋友了。那么今天我就带大家走近这位老朋友,看看它是如何处理网络请求的,以及它的内部架构。这对于帮助我们了解Tomcat的使用会有很大的好处。

Web容器和TomcatTomcat连接器Tomcat容器

Web 容器与 Tomcat

要清楚地解释Tomcat的作用,我们首先要从早期的Web应用程序开始。

图1:浏览器通过HTTP服务器获取静态资源

如图1所示,最初用户通过浏览器查看新闻等静态资源。这时需要通过HTTP服务器将静态HTML资源返回给浏览器,浏览器将解析后的HTML呈现给用户。

这里的Web容器用于存放HTTP服务器,可以处理网络请求并响应。

随着互联网的发展,用户需求已经从静态资源获取转向动态资源获取。同时浏览器在获取资源的同时也会与服务器进行交互。

从那时起,Web容器的功能开始扩展。 HTTP服务器除了能够处理HTTP请求之外,还需要调用服务器程序,通常称为Web应用程序。

图2:通过HTTP 服务器调用Web 应用程序

针对这种需求,Sun推出了Servlet技术。 Servlet是运行在服务器端的Java小程序。

由于Servlet无法独立运行,因此需要一个Servlet容器来承载它,并进行初始化、启动等管理操作。

图3:Servlet容器介绍

如图3所示,为了满足用户日益增长的需求,Servlet作为Web应用程序添加到Web容器中,为用户提供动态资源。

为了托管Servlet,还添加了Servlet 容器。然而,每个Servlet代表一个业务类并包含一些业务应用程序。如果都接入Web容器,用户就需要遵循统一的接口来提供统一的服务响应。

说白了,必须遵循一定的规则,才能放入Servlet容器中,方便管理。那么这条规则就是Servlet接口。从图中可以看出,Servlet接口为单个Servlet提供了标准定义。

图4:Servlet 界面

如图4所示,对于Servlet接口,定义了init方法用于Servlet资源的初始化,同时还定义了destroy方法用于Servlet资源的释放。

Service方法用于实现特定的业务需求。可以看到这个方法传入了两个参数,ServletRequest和ServletResponse,分别代表对用户的请求信息和Servlet的响应信息的封装。

后面我们会介绍,Spring MVC在Tomcat中运行时也是作为Servlet存在的,Spring MVC容器是在init方法中由DispatcherServlet创建的。

接口中的getServletConfig方法将返回ServletConfig。 ServletConfig用于封装Servlet的初始化参数。您可以在web.xml中配置Servlet参数,然后通过getServletConfig方法获取参数。

上面介绍了Servlet接口,接下来通过图5来深入了解Servlet接口调用的外围类。

图5:Sevlet 类图

如图5所示,Servlet接口依赖于ServletConfig接口,该接口用于处理Servlet配置参数。 ServletConfig接口还与ServletContext关联来获取Servlet上下文信息。

Servlet接口中的service方法依赖于两个参数:ServletRequest和ServletResponse。

有两个接口HttpServletRequest和HttpServletResponse,分别继承了ServletRequest和ServletResponse。

一般来说,Servlet作为一个接口需要有一个具体的实现类来实现这个接口,因此Servlet规范提供了一个名为GenericServlet的抽象类,它实现了Servlet。

然后还有一个继承GenericServlet的HttpServlet类。为了处理HTTP请求,该类还依赖于HttpServletRequest和HttpServletResponse。

Servlet接口定义是Servlet容器的重要组成部分。 Servlet容器通过接口管理所连接的Servlet实体。

接下来我们看一下Servlet容器的分类。这里,Servlet容器根据工作模式分为3类:

独立运行的 Servlet 容器

在此模式下,Servlet 容器构成Web 服务器的一部分。使用Java Web 服务器时使用此模式。这也是Tomcat的默认模式。如果Web服务不是基于Java的,则需要使用以下两种模式。

内置的 Servlet 容器

Servlet容器由两部分组成:Web服务器插件和Java容器。您需要在Web服务器的内部地址空间中打开一个JVM,在该JVM上加载Java容器,并运行servlet。

当容器请求一个Servlet时,Web服务器插件会请求JVM上加载的Servlet,通过JNI技术将请求传递给Java容器,然后Java容器将请求传递给Servlet进行处理。

外置的 Servlet 容器

Servlet 容器在Web 服务器外部的地址空间中运行。通过Web服务器插件在Web服务器外部的地址空间中打开一个JVM,加载Java容器来运行Servlet。 Web 服务器插件和JVM 使用IPC(进程间通信)机制进行通信。

Web服务器通过IPC技术将请求传递给Java容器,然后Java容器将请求交给Servlet处理。

了解了Servlet接口规范和Servlet容器后,我们知道如果我们需要加载不同的动态资源(Web应用),就需要使用Servlet容器来加载对应的Servlet。这个加载过程是如何进行的?

接下来我们看一下Servlet的请求和响应过程。

图6:Servlet请求和响应流程

如图6所示,HTTP请求和响应过程分为8个步骤:

用户通过浏览器发起HTTP请求。 Servlet容器收到请求后会解析HTTP请求。根据解析结果和配置信息创建Servlet 实例。实例创建完成后,调用Servlet实例的init方法完成实例初始化。接下来就是调用Servlet中的Service方法来完成具体的业务。 Service方法完成后,会将响应信息返回给Servlet容器。 Servlet容器将Servlet返回的信息创建为HTTP响应并将其返回给浏览器。最后,Servlet容器调用destroy方法卸载Servlet并释放相应的资源。我在这里为您写一个部分。 Web容器用于提供Web服务器。当用户请求Web容器时,HTTP请求将通过HTTP服务器进行解析,然后将解析后的请求交给Servlet容器。

Servlet容器负责定义Servlet接口规范并管理Servlet程序。所有Web应用程序都将以Servlet的形式存在。每个Servlet都需要遵循Servlet接口的定义,按照Servlet处理流程响应用户请求。

Tomcat就是这里展示的Web容器,上面提到的原理和流程都是Tomcat的工作。

简单来说,Tomcat=HTTP服务器+Servlet容器(Servlet接口规范)。 Servlet只要服务于Servlet接口,就可以运行在Tomcat上,并向外界提供服务。

Tomcat 连接器

上一节介绍了Tomcat的设计思想。 Tomcat作为Web容器,实现了HTTP服务器和Servlet容器的功能。

因此,可以概括为两大功能:

第一个进程是Socket连接,负责将网络请求解析成相应的Request和Response对象。第二个加载并管理Servlet,处理请求并返回响应。因此引入了Tomcat的两个核心组件:Connector和Container。 Connector负责对外通信,容器负责内部Servlet的管理。

图7:Tomcat 连接器和容器

如图7所示,当浏览器向Tomcat发送Request时,连接器会对其进行解析,生成相应的ServletRequest,并将其传递给容器进行处理。

容器完成处理后,会返回连接器ServletResponse。同样,连接器会将ServletResponse解析为Response并将其返回给浏览器。

介绍完前面的连接器和容器的关系之后,我们来重点了解一下连接器支持的三种应用层协议:

HTTP/1.1 协议:这是绝大多数Web 应用程序使用的访问协议。主要用于Tomcat单独运行(不与Web服务器集成)时使用。 AJP协议:用于与Web服务器(如Apache HTTP Server)集成,实现静态资源的优化和集群部署。目前支持AJP/1.3。 HTTP/2.0协议:Tomcat 8.5、9.0版本开始支持下一代HTTP协议。目前最新主流版本已支持HTTP/2.0。上面我们已经了解了Tomcat用来接收网络请求的协议。接下来我们将介绍连接器收到网络请求后的动作。

Tomcat 连接器通过以下组件处理网络请求:

Endpoint:作为连接器的通信端点,负责监听通信端口。它实现了Socket接收处理类,并对传输层进行了抽象。

因为网络通信的I/O模型包括:非阻塞I/O、异步I/O或者APR。应用层协议包括:HTTP、HTTPS、AJP。

Processor:负责将接收到的网络请求构造成Request和Response对象,并通过Adapter提交给容器处理。

如果说Endpoint是用来实现TCP/IP协议的,那么Processor就是用来实现HTTP协议的。 Processor可以理解为应用层的抽象。 Processor是单线程的,Tomcat在同一个连接中复用该Processor。

Tomcat根据不同的协议提供了3个实现类:

Http11Processor(HTTP/1.1)AjpProcessor(AJP)StreamProcessor(HTTP/2.0)也提供了两种实现:

UpgradeProcessorInternal,用于处理内部支持的升级协议(例如HTTP/2.0和WebSocket)。 UpgradeProcessorExternal,用于处理外部扩展的升级协议支持。ProtocolHandler:是Endpoint和Processor的抽象。由于Endpoint负责I/O模型,Processor负责应用层协议,因此两者会结合在一起工作,比如NIO+HTTP或者NIO2+AJP。

所以两者是通过ProtocolHandler进行封装的,封装的也是两者结合带来的变化。例如:Http11NioProtocol 和AjpNioProtocol。

如图8所示,Tomcat设计了一个抽象基类来封装这部分。抽象基类AbstractProtocol 实现ProtocolHandler 接口。

图8:ProtocolHandler封装Endpoint和Processor

每个应用层协议都有自己的抽象基类,例如AbstractAjpProtocol和AbstractHttp11Protocol。

Adapter:负责请求转换,将Tomcat的Request对象转换为ServletRequest对象。

由于Tomcat可以加载任何符合Servlet接口规范的Servlet实例,因此需要使用ServletRequest对象与其进行通信,因此需要使用该组件来完成对request对象的适配。

之前我们已经介绍过Tomcat连接器的几个组件。这里我们梳理一下连接器处理请求的流程,如图9所示。

图9:Tomcat 连接器

用户通过浏览器向Tomcat发起请求,连接器通过Endpoint接收请求,通过I/O模型进行处理,然后将结果交给Processor。

Processor进行应用层协议处理,然后将请求交给Adapter,Adapter将适配后的ServletRequest发送给容器处理。

Tomcat 容器

上面我们讲了Tomcat的Connector,它承载了处理网络IO请求和协议处理的工作,并向容器发送请求适配。

接下来我们看一下Tomcat容器需要完成的工作。首先我们看一下容器的构成,如图10所示:

图10:Tomcat 容器

Tomcat 容器将包含一个Engine 容器。一个Engine容器可以包含多个Host容器,每个Host容器可以包含多个Context容器。也就是说Host可以包含多个应用,每个应用对应一个Context容器。

作为一个应用程序,每个Context容器可以包含多个Wrapper容器:每个Wrapper容器都包含一个Servlet容器,这意味着Tomcat允许一个应用程序有多个Servlet实现。

介绍完Tomcat的容器组成,我们知道它是由Engine、Host、Context和Wrapper组成,并且知道它们之间的包含关系。接下来我们看看各个组件需要完成的工作。

Tomcat的四个容器结构相同,包括:

Pipeline:用于处理请求中的信息。每条管道包含多个阀门。每个Valve都有相同的方法invoke(Request请求,Response响应)。在该方法中,可以处理请求中的信息。BaseValve:基本阀门,其方法与Piple中的阀门值相同:invoke(Request request, Response response)。它的主要作用是连接父子容器,并将父容器的请求传递给子容器。假设Servlet是处理最终请求的实体,那么请求可以想象为从Engine到Host再到Context最后到Wrapper的传输链。

这条链通过Pipeline连接起来。链中的处理节点是阀门Value,各链之间的连接点是基础阀门BaseValue。

图11:Tomcat容器之间的信息传输

信息通过Engine中的Pipeline传递,其中Value是阀门,可以通过invoke方法处理请求信息。

信息经过Pipeline中的阀门后,会通过基础阀门,即BaseValue传递到下一个容器组件Host。 Host也会以同样的方式将信息通过Context一层层传递给Wrapper。

Engine

Tomcat中的连接器接受并解析消息后,会将消息传输到Engine容器。用户可以将各种定制的Valve添加到Engine容器的Pipeline中,Engine容器会一一调用Pipeline中的Valve。

Engine容器的BaseValve是StandardEngineValve。这个Valve会读取Request中的Host信息,然后将请求路由到对应的Host容器。

Host

Host是Engine的子容器。每个Host容器都是一个对应不同域名的虚拟主机。

从1.1开始,HTTP协议支持在请求头中添加Host字段来表示请求的域名。

Host通过解析这个域名来决定如何将请求发送到不同的Host。 DNS域名解析时,不同的域名可以解析到同一个IP或主机。

Engine容器的BaseValve会读取Request中的Host,然后调用对应Host容器的Pipeline来处理消息。

假设Tomcat支持三个域名:

http://www.a.comhttp://www.b.comhttp://www.c.com在Tomcat的配置文件server.xml中的Engine标签下添加多个Host标签。

如图12所示,配置中Host节点中的name代表域名,appbase代表虚拟主机的目录。

图12:主机配置

当我们在浏览器中输入http://www.a.com时,Tomcat通过读取server.xml中的配置信息找到www.a.com对应的虚拟主机Host,然后使用找到的Host来处理请求。

Context

表示在虚拟主机上运行的Web 应用程序。每个Web应用程序都是基于一个WAR文件,或者是WAR文件解压后对应的目录(这里称为应用程序目录)。 Context是Host的子容器,每个Host可以根据需要定义任意多个Context元素。

Wrapper

是最小的容器,每个Wrapper对应一个Servlet实例。

Tomcat容器的四个组件已经给大家一一介绍了。这里我通过一个例子带大家了解一下请求容器的过程。

图13:Tomcat容器执行流程

如图13所示:

假设浏览器向Tomcat连接器发送请求,向www.a.com网站发送GET请求,请求内容为/AppA/ServletA。 Connector根据指定的协议和IO方式处理请求Socket消息,将Socket解析成对应的Request实体,并传递给容器中的Engine。连接器将请求交给Engine容器,Engine容器中存储了请求的域名与Host容器的映射关系。找到‘www.a.com’域名对应的Host容器,将请求交给对应的Host。 Host容器继续解析请求中的路径。如果配置了路径和应用程序的关系,比如'/AppA'对应的Context容器,则会安装并配置Host容器,将请求交给对应应用程序的Context容器。 Host容器解析出路径并将应用程序交给Context容器后,不同的请求就可以通过该路径映射到不同的Servlet容器。例如图中的'/ServletA'对应的是Wrapper容器,Context容器将请求交给Wrapper容器。然后Wrapper容器会加载对应的ServletA实现类,调用Servlet实现类中的逻辑来处理Request,并将处理结果写入到Response中。

总结

因此,HTTP服务器和Servlet容器的功能构成了Web应用程序。这就是Tomcat的实现原理。

然后介绍Tomcat的两个重要组件:连接器和容器。连接器处理IO 模型和传输协议并执行请求适配。

容器包括Engine、Host、Context、Wrapper,并描述了它们的父子关系以及各个组件的功能。通过一个例子来描述容器组件之间请求传输的过程。

征稿:如果您有兴趣提交文章或寻求报道,请联系editor@51cto.com

用户评论

走过海棠暮

学习tomcat真的很有挑战,需要仔细研究才能搞定啊

    有14位网友表示赞同!

北朽暖栀

现在做开发确实要掌握好tomcat的使用,太重要了!

    有19位网友表示赞同!

各自安好ぃ

感觉这篇文章应该分享一些具体的解决问题的方法,这样大家能更容易理解

    有20位网友表示赞同!

何年何念

51CTO的博客文章质量一直不错,值得一看

    有13位网友表示赞同!

南宫沐风

搞定tomcat可以做更多高级的功能开发了吧!

    有10位网友表示赞同!

心亡则人忘

看完标题就兴奋了,这篇文章肯定干货满满

    有15位网友表示赞同!

剑已封鞘

希望这篇文章能讲明白一些基础知识,让我也能跟上节奏

    有14位网友表示赞同!

哭花了素颜

Tomcat感觉越来越常用,学习起来还是挺有用的

    有6位网友表示赞同!

巴黎盛开的樱花

分享这种搞定tomcat的经验和技巧真是太好了,让我更容易入门

    有14位网友表示赞同!

有一种中毒叫上瘾成咆哮i

做开发真的要熟练掌握这些工具,感觉这篇文章很实用!

    有11位网友表示赞同!

泡泡龙

看到"搞定"就觉得很棒,这个标题很有吸引力啊!

    有20位网友表示赞同!

陌潇潇

学习tomcat是一个很好的方向,能提升自己的编程水平

    有15位网友表示赞同!

采姑娘的小蘑菇

希望还有更多关于Tomcat的分享,让我可以更深入地了解它

    有13位网友表示赞同!

肆忌

文章内容看起来很专业,期待详细讲解和案例分析

    有18位网友表示赞同!

你tm的滚

喜欢这类干货满满的文章,读完后能学到新知识!

    有14位网友表示赞同!

陌上花

在做web项目的时候经常用到tomcat,学习起来很重要

    有15位网友表示赞同!

幸好是你

这种分享很有帮助,让我更加了解Tomcat的应用场景

    有12位网友表示赞同!

算了吧

期待阅读这篇文章,希望能获得一些实用的技巧

    有8位网友表示赞同!

相知相惜

做Web开发必须要掌握tomcat,这篇博客应该很有帮助

    有16位网友表示赞同!

╭摇划花蜜的午后

学习新的技术总令人兴奋,搞定tomcat感觉很棒!

    有10位网友表示赞同!

本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/8070.html

联系我们

在线咨询:点击这里给我发消息

微信号:666666