本章节为介绍如何安装Tomcat工具以及其主要架构知识概念,深入浅出让新人玩家理解为什么选择该容器以及该容器的优点
web服务器
概念
服务器:安装了服务器软件的计算机
服务器软件:接收用户的请求,处理请求,做出响应
web服务器软件:接收用户的请求,处理请求,做出响应。
在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
常见web服务器软件
1、webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费。
2、websphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费。
3、JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费。
4、Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源、免费。
Tomcat
一、Tomcat 安装
下载
https://tomcat.apache.org/download-80.cgi
apache-tomcat-8.5.42-windows-x64.zip
安装
将下载的.zip 压缩包解压到系统的目录(建议是没有中文不带空格的目录)下即可。
目录结构如图:
二、Tomcat源码
下载
地址:https://tomcat.apache.org/download-80.cgi
apache-tomcat-8.5.42-src.zip
运行
1)解压zip压缩包
2)进入解压目录,并创建一个目录,命名为home ,并将conf、webapps日录移入home目录中
3)在当前目录下创建一个pom.xml文件,引入tomcat的依赖包
HTTP服务器的请求处理原理
servlet容器的工作流程
HTTP服务器不直接调用servlet,而是把请求交给servlet容器来处理
问:那servlet容器是怎么工作的?
当客户请求某个资源时,HTTP服务器会用一个servletRequest对象把客户的请求信息封装起来,然后调用servlet容器的service方法,
servlet容器金到请求后,根据请求的URI和servlet的映射关系,找到相应的servlet,如果servlet还没有被加载,就用反射机制创建这个servlet,
并调用servlet的init方法来完成初始化,接着调用servlet的service方法来处理请求,把servletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给客户端。
三、Tomcat整体架构
我们知道如果要设计一个系统,首先是要了解需求,而我们已经了解了Tomcat要实现两个核心功能:
1)处理socket连接,负责网络字节流与Request和Response对象的转化。
2)加载和管理servlet,以及具体处理Reguest请求。
因此Tomcat设计了两个核心组件连接器(connector)和容器(container)来分别做这两件事情,连接器负责对外交流,容器负责内部处理。
连接器Coyote
Coyote 是Tomcat的连接器框架的名称,是Tomcat服务器提供的供客户端访问的外部接口。
客户端通过Coyote与服务器建立连接、发送请求并接受响应。
1)Coyote封装了底层的网络通信(Socket 请求及响应处理),为Catalina 容器提供了统一的接口,使Catalina容器与具体的请求协议及I0操作方式完全解耦。
2)Coyote将Socket输入转换封装为Request对象,交由catalina容器进行处理,处理完成后,Catalina 通过Coyote提供的Response对象将结果写入输出流。
3)Coyote作为独立的模块,只负责具体协议和I0 的相关操作,与Servlet规范实现没有直接关系,因此即便是Request和Response对象也并未实现servlet规范对应的接口,
而是在Catalina中将他们进一步封装为servletRequest 和ServletResponse。
Io模型与协议
在Coyote中
Tomcat支持的多种I/O模型和应用层协议,具体包含的IO模型和应用层协议,看下表
Tomcat支持的IO模型(自8.5/9.0 版本起,Tomcat 移除了 对 BI0 的支持):
IO模型 | 描述 |
---|---|
NIO | 非阻塞I/0,采用Java NIo类库实现。 |
NIO2 | 异步I/0,采用JDK 7最新的NIO2类库实现。 |
APR | 采用apache可移植运行库实现,是c/c++编写的本地库。如果选择该方案,需要单独安装APR库 |
Tomcat 支持的应用层协议:
应用层协议 | 描述 |
---|---|
HTTP/1.1 | 这是大部分web应用采用的访问协议。 |
AJP | 用于和web服务器集成(如Apache),以实现对静态资源的优化以及集群部署,当前支持AJP/1.3。 |
HTTP/2 | HTTP 2.0大幅度的提升了web性能。下一代HTTP协议,自8.5以及9.0版本之后支持。 |
Tomcat中的组件
一、连接器组件
连接器的组件对数据处理的流程简介
客户端发起的Socket请求会被EndPoint接收并且会把请求发送给处理器processor,processor在接受到请求之后将该请求转换成http协议的请求,
并将http的请求进行解析封装成request对象,但是容器需要的是ServletRequest对象,所以Tomcat用到了设计模式-适配器设计模式,先调用adapter(适配器)的转换方法将Request对象转换成servletRequest对象再传输给容器。
连接器中的各个组件的作用
1、EndPoint组件
1、EndPoint:Coyote通信端点,即通信监听的接口,是具体Socket接收和发送处理器,是对传输层的抽象,因此Endpoint用来实现TCP/IP协议的。
2、Tomcat并没有Endpoint接口,而是提供了一个抽象类abstractEndpoint,里面定义了两个内部类:acceptor和Socketprocessor。
Acceptor用于监听Socket连接请求。socket processor用于处理接收到的socket请求,它实现Runnable接口,在Run方法里调用协议处理组件processor进行处理,为了提高处理能力,
socketprocessor被提交到线程池来执行。而这个线程池叫作执行器(Executor),(后面再详细介绍Tomcat如何扩展原生的Java线程池)
2、Processor组件
Processor:Coyote协议处理接口如果说Endpoint是用来实现TCP/IP协议的,那么Processor用来实现HTTP协议,Processor接收来自Endpoint的socket,
读取字节流解析成Tomcat Recuest和Response对象,并通过Adapter将其提交到容器处理,processor是对应用层协议的抽象。
3、ProtocolHandler组件
ProtocolHandler:Coyote协议接口,通过Endpoint和Processor ,实现针对具体协议的处理能力。Tomcat按照协议和I/O 提供了6个实现类:
AjpNio2Protocol、AjpAprProtocol、Http11Nio2Protocol、AjpNio2Protoco1,Http11NioProtoco1、Http11Aprprotocol,在配置tomcat/conf/server.xml 时,至少要指定具体的ProtocolHandler,当然也可以指定协议名称,如:HTTP/1.1,如果安装了APR,那么将使用nttp11Aprprotocol ,否则使用 Http11Nioprotocol
4、Adapter组件
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来”存放”这些请求信息。Protoco1Hand1er接口负责解析请求并生成Tomcat Reguest类。但是这个Reguest对象不是标准的servletReguest,也就意味着,不能用omcat Request作为参数来调用容器。Tomcat设计者的解决方案是引入coyoteAdapter,这是适配器模式的经典运用,连接器调用covoteAdapter的Sevice方法,传入的是Tomcat Request对象,CoyoteAdapter负责将Tomcat Reguest转成servletRequest,再调用容器的service方法。
二、容器-Catalina
概念
如果说coyote是负责具体的协议的解析,那么 Catalina就是对最终的请求逻辑进行处理。
介绍
Tomcat是一个由一系列可配置的组件构成的web容器,而catalina是Tomcat的servlet容器
catalina是servlet容器实现,包含了之前讲到的所有的容器组件,以及后续章节涉及到的安全、会话、集群、管理等servlet 容器架构的各个方面。
它通过松耦合的方式集成coyote,以完成按照请求协议进行数据读写。同时,它还包括我们的启动入口、shell程序等。
Catalina的地位可以通过下图的Tomcat的分层结构示意图来帮助了解
微总结
Tomcat 本质上是一款Servlet 容器,因此Catalina才是Tomcat的核心其他模块都是为Catalina提供支撑的。
比如通过Coyote模块提供链接通信,Jasper 模块提供JSP引擎,Naming 提供JNDI 服务,Juli提供日志服务。
结构
为帮助理解Catalina的结构用下图进行展示
如上图所示,catalina负责管埋server,而server表示着整个服务器。server下面有多个服务service,每个服务都包含着多个连接器组件connector(coyote实现)和一个容器组件container。在Tomcat 启动的时候, 会初始化一个catalina的实例。
Catalina各组件的职责
组件 | 职责 |
---|---|
Catalina | 负责解析Tomcat的配置文件:,以此来创建服务器server组件,并根据命令来对其进行管理 |
Server | 服务器表示整个catalina servlet容器以及其它组件,负责组装并启动servlet引擎,Tomcat连接器。server通过实现Lifecycle接口,提供启动和关闭整个系统的方式 |
Service | 服务是server内部的组件,一个server包含多个service。它将若干个connector组件绑定到一个Container(Engine)上 |
Connector | 连接器,处理与客户端的通信,它负责接收客户请求,然后转给相关的容器处理,最后向客户返回响应结果 |
Container | 容器,负责处理用户的servlet请求,并返回对象给web用户的模块 |
1、Container容器结构说明 | |
Tomcat设计了4种容器,分别是Engine、Host、Context和wrapper。这4种容器不是平行关系,而是父子关系。 | |
Tomcat通过一种分层的架构,使得servlet容器具有很好的灵活性。 | |
也可以再通过tomcat的server.xml配置文件来加深对Tomcat容器的理解。
Tomcat采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是server,其他组件按照一定的格式要求配置在这个顶层容器中。
<service>
<Connector/>
<Connector/>
<Engine>
<Host>
<Context></Context>
</Host>
</Engine>
</service>
</server>
Tomcat是如何管理这些容器的?
这些容器具有父子关系,形成一个树形结构,在这里你可能马上就想到了设计模式中的组合模式。
没错Tomcat就是用组合模式来管理这些容器的。
具体实现方法是,所有容器组件都实现了container接口,因此组合模式可以使得用户对单容器对象和组合容器对象的使用具有一致性,
这里单容器对象指的是最底层的wrapper,组合容器对象指的是上面的context、Host或者Engine。
三、Tomcat 启动流程
1、启动步骤:
1)启动tomcat需要调用 bin/startup.bat(在linux目录下,需要调用 bin/startup.sh)在startup.bat 脚本中调用了catalina.bat。
2)在Catalina.bat脚本文件中调用了 Bootstrap 中的main方法。
3)在Bootstrap的main方法中调用了 init 方法来创建catalina 及 初始化类加载器。
4)在Bootstrap的main方法中调用了 load 方法,在其中又调用了catalina的load方法。
5)在catalina的load方法中,需要进行一些初始化的工作,并需要构造Digester 对象,用于解析XML.然后在调用后续组件的初始化操作。。。
其实就是加载Tomcat的配置文件,初始化容器组件,监听对应的端口号,准备接受客户端请求。
2、源码解析:
lifecycle
由于所有的组件均存在初始化、启动、停止等生命周期方法,拥有生命周期管理的特性,所以Tomcat在设计的时候,基于生命周期管理抽象成了一个接口lifecycle,
而组件server、service、container、Executor、connector 组件,都实现了一个生命周期的接口,从而具有了以下生命周期中的核心方法:
init():初始化组件
start():启动组件
stop():停止组件
destroy():销毁组件
各组件的默认实现
上述的server、service、Engine、Host、context都是接口,下图中罗列的这些接口的默认实现类。
当前对于Endpoint组件来说,在Tomcat中没有对应的Endpoint接口,但是有一个抽象类AbstractEndpoint,其下有三个实现类:
NioEndpoint、Nio2Endpoint、AprEndpoint这三个实现类,分别对应于前面的链接器Coyote提到的链接器支持的三种IO模型:
NIO,NIO2,APR,Tomcat8.5版本中,默认采用的是 NioEndpoint。
ProtocolHandler:Coyote协议接口,通过封装Endpoint和Processor(相当于Endpoint和Processor组合的组件)实现针对具体协议的处理功能。
Tomcat按照协议和IO提供了6个实现类:
AJP协议:
1)AjpNioProtocol :采用NIO的IO模型
2)AjpNio2protocol:采用NI02的IO模型
3)Ajpaprprotocol :采用APR的IO模型,需要依赖于APR库
HTTP协议:
1)Httpl1NioProtocol:采用NIO的Io模型,默认使用的协议(如果服务器没有安装APR)。
2)Http11Nio2Protoco1:采用NIO2的IO模型。
3)Httpl1aprProtocol:采用APR的IO模型,需要依赖于APR库。
启动流程(暂时先不做补充)
https://www.bilibili.com/video/BV1dJ411N7Um?p=13&spm_id_from=pageDriver&vd_source=ae9c1573e924540a89e008b340e54657
xxx
xxx
xxx
请求处理流程
设计了这么多层次的容器,Tomcat是怎么确定每一个请求应该由哪个Wrapper容器里的servlet来处理的呢?
答案是,Tomcat是用Mapper组件来完成这个任务的。
Mapper组件的功能是将用户请求的URL定位到一个servlet,它的工作原理是在Mapper组件里保存了web应用的配置信息,也就是容器组件与访问路径的映射关系,比如:
Host容器里配置的域名、context容器里的neb应用路径,以及wrapper容器里servlet映射的路径,可以理解为这些配置信息就是一个多层次的Map。
当一个请求到来时Mapper组件通过解析请求URL里的域名和路径,再到自己保存的Map里去查找,就能定位到一个servlet。
注意。一个请求URL最后只会定位到一个wrapper容器,也就是一个servlet。
下面的示意图中就描述了 当用户请求链接 http://www.itcast.cn/bbs/findA11之后,是如何找到最终处理业务逻辑的servlet。