Tomcat 原理浅析

web 基本概念

web 资源分类

  • 静态资源:所有用户访问后,得到的结果都是一样的。静态资源可以直接被浏览器解析(html、css、js)。
  • 动态资源:不同用户访问相同的资源后,得到的结果可能是不一样的。原理是动态资源被访问后, 先转换为静态资源,再返回给浏览器解析(servlet/jsp、php、asp),所以并不存在真正的动态资源。

HTTP 工作流程

  1. 用户在页面进行某一操作
  2. 浏览器和服务器建立连接
  3. 浏览器给服务器发送请求
  4. 服务器处理请求,并将执行结果响应给浏览器
  5. 浏览器解析服务器返回的结果,并展示给用户

HTTP 服务器

能够处理 HTTP 请求的服务器就是 HTTP 服务器,市面上常见的服务器有以下几款:

  • 收费:webLogic(oracle 公司)、webSphere(IBM 公司)、JBOSS(JBoss 公司),这三款都是大型的 JavaEE 服务器,支持所有的 JavaEE 规范。
  • 免费:Tomcat(Apache 基金组织),中小型 JavaEE 服务器,仅支持少量的 JavaEE 规范的 servlet/jsp。

 

Tomcat 架构

HTTP 请求处理

图1:由 HTTP 服务器直接调用具体业务类处理 HTTP 请求,需要在 HTTP 服务器中编写代码,服务器和业务类紧耦合。

图2:HTTP 服务器不直接调用业务类,而是把请求交给容器来处理,容器通过 Servlet 接口调用业务类。因此 Servlet 接口和 Servlet 容器的出现,达到了 HTTP 服务器和业务类解耦的目的。而 Servlet 接口和 Servlet 容器的这一整套规范叫作 Servlet 规范(JaveEE 13 规范之一)。

Tomcat 按照 Servlet 规范的要求实现了 Servlet 容器,同时它也具有 HTTP 服务器的功能。如果要实现新的业务功能,只需要实现一个 Servlet 接口,并把它注册到 Tomcat(Servlet 容器)中,剩下的事情就由 Tomcat 帮我们处理了。

JavaEE 13个核心规范

Servlet 容器工作流程

当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来,然后传递给 Servlet 容器,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet,如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化,接着调用 Servlet 的 service 方法(get、post ...)来处理请求,并将 ServletResponse 对象返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端。

Tomcat 整体架构

综上所述,我们可以发现 Tomcat 有两个核心功能:

  1. 处理 socket 连接,负责网络字节流与 Request 和 Response 对象的转化。
  2. 加载和管理 Servlet,以及具体处理 Request 请求。

因此 Tomcat 设计了两个核心组件:连接器(Connector)和容器(Container)。

连接器负责对外交流,容器负责内部处理。一个容器可以对应多个连接器,连接器和容器都不能单独的对外提供服务,所以 Tomcat 以 service 的形式对外提供服务,一个 service 中至少包含一个连接器和一个容器。

Tomcat 包含模块如下:

四张图带你了解Tomcat系统架构

Tomcat目录结构

 

连接器、容器

Coyote

Coyote 是 Tomcat 服务器提供的供客户端访问的外部接口,客户端通过 Coyote 与服务器建立连接、发送请求并接受响应。

Coyote 封装了底层的网络通信(Socket,请求以及响应处理),为 Catalina 容器提供了统一的接口,使 Catalina 容器与具体的请求协议以及 IO 操作方式完全解耦

需要注意的是,Coyote 作为独立模块,负责具体协议和 IO 的相关操作,与 Servlet 规范实现没有直接的关系,因此即便是 Request 和 Response 对象也并未实现 Servlet 规范对应的接口,而是在 Catalina 中将他们进一步封装为 ServletRequest 和 ServletResponse。

网络/IO基础

IO 模型与协议

连接器组件

EndPoint:Coyote 通信监听接口,具体的 Socket 接收和发送处理器,是对传输层的抽象。

Processor:Coyote 协议处理接口,实现 HTTP 协议。接收来自 EndPoint 的 Socket,读取字节流解析成 Request 和 Response 对象,是对应用层协议的抽象。

Adapter:由于 Request 并没有实现 Servlet 规范,而 Servlet 容器只能接收 ServletRequest,因此需要引入一个适配器将 Request 转换成 ServletRequest,再传递给 Servlet 容器。

适配器模式原理及实例介绍

Catalina

整体架构

如上图所示,Catalina 负责管理 Server,而 Server 表示整个服务器,Server 下面有很多服务 Service,每个服务都包含着多个连接器组件 Connector(Coyote 实现)和一个容器组件 Container。在 Tomcat 启动时,会初始化一个 Catalina 的实例。

Container 结构

 

 

时序图

启动流程时序图

请求调用时序图

用户一个请求从 URL 到定位到某一个具体的 Servlet,是由 Mapper 组件来完成这个任务的。它的工作原理是保存了 Web 应用的配置信息(容器组件与访问路径的映射关系),比如 Host 容器里配置的域名、Context 容器里的 Web 应用路径以及 Wrapper 容器里 Servlet 的映射的路径,这个信息可以想象成一个多层次的 Map。

假设来自客户的请求为:http://localhost:8080/wsota/wsota_index.jsp。

  1.  请求被发送到本机端口 8080,被在那里侦听的 Coyote HTTP/1.1 Connector 获得
  2.  Connector 把该请求交给它所在的 Service 的 Engine 来处理,并等待来自 Engine 的回应
  3.  Engine 获得请求 localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机 Host
  4.  Engine 匹配到名为 localhost 的 Host(即使匹配不到也把请求交给该 Host 处理,因为该 Host 被定义为该 Engine 的默认主机)
  5.  localhost Host 获得请求 /wsota/wsota_index.jsp,匹配它所拥有的所有 Context
  6.  Host 匹配到路径为 /wsota 的 Context
  7.  path=/wsota 的 Context 获得请求 /wsota_index.jsp,在它的 mapping table 中寻找对应的 servlet
  8.  Context 匹配到 url pattern 为 *.jsp 的 servlet,对应于 JspServlet 类
  9.  构造 HttpServletRequest 对象和 HttpServletResponse 对象,作为参数调用 JspServlet 的 doGet 或 doPost 方法
  10. Context 把执行完了之后的 HttpServletResponse 对象返回给 Host
  11. Host 把 HttpServletResponse 对象返回给 Engine
  12. Engine 把 HttpServletResponse 对象返回给 Connector
  13. Connector 把 HttpServletResponse 对象返回给客户 browser

 

Jasper

客户端访问一个 jsp 文件,最终接收到的响应还是 html、css 和 js 代码,因此 jsp 可以看做是一个运行在服务端的脚本。

而 Jasper 的作用就是对 jsp 语法进行解析,生成 servlet 并生成 class 字节码文件,最终将访问的结果直接响应客户端。

因此客户端发送请求之后就会刷新页面,是因为 jasper 直接返回了一个全新的 html 代码。 

Jasper 配置

Tomcat 在默认的 web.xml 中配置了一个 JspServlet,用于处理所有的 .jsp 或者 .jspx 结尾的请求:

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

jsp 请求处理流程

生成 java、class 流程图:

 

Tomcat 配置

server.xml

  • Executor:Connector 线程池配置。若不配置,每个 Connector 使用自己的线程池;可以通过配置使 Connector 使用共享线程池。
  • Engine:默认访问名为 localhost 的主机下的资源。
  • Host:指定主机名(若配置为 www.xxxx.com,需要能被 host 或者 dns 解析)、资源位置。
  • Context:指代 Web 应用,Web 应用基于 WAR 文件,或 WAR 文件解压后对应的目录。由于 Tomcat 能够自动部署,所以该标签的 docBase 属性不需要指定,由 Tomcat 根据目录名称自动推导。

详解Tomcat 配置文件server.xml

web.xml

tomcat 配置文件中有一份,用户自己的项目工程中也可以配置一份。

  • context-param:配置 tomcat 初始化参数。
  • session-config:配置 session 相关的参数,甚至可以修改默认的 JSESSIONID 名字。
  • error-page:可以配置 error-code 或者 exception-type。

关于web.xml配置的那些事儿

HTTP常见状态码 200 301 302 404 500

tomcat-users.xml

可以配置用户。访问 webapps 中的 host-manager 和 manager 时,需要在该文件中配置指定的用户角色。

 

Tomcat 集群

环境搭建

Nginx + Tomcat:

  • Nginx 配置 serverpool
  • Tomcat 三个端口号修改

负载均衡:权重、ip_hash(根据 ip 计算出一个 hash 值,决定访问哪台 Tomcat)

session 共享策略:ip_hash、Tomcat 配置广播(如果集群很大,会造成广播风暴)、SSO 单点登录(推荐)。

关于 session 共享,现在也有 JWT  — — 即服务端放弃 session,客户端使用一个 JSON 字符串保存客户信息,每次发送请求发送到服务端。 

安全配置

  1. 删除 webapps 目录下的所有文件,禁用 tomcat 管理界面。
  2. 删除 tomcat-uesrs.xml 文件呢id所有用户权限。
  3. 更改关闭 tomcat 指令(例如 8005 端口的 shundown 指令可以关闭 Tomcat)
  4. 定义错误页面,不让用户看到错误信息,从而推测出系统的架构信息。

应用安全

基本包含两个部分:认证(登录/单点登录)和授权(功能权限、数据权限)。

推荐框架 SpringSecurity、Apache Shiro。

传输安全

对存在敏感信息的页面,使用 HTTPS 协议。

性能测试

免费工具:ApacheBench、ApacheJMeter

收费:WCAT、WebPloygraph、LoadRunner

吞吐量:每秒执行的请求数。

配置调优

JVM 内存、垃圾挥手配置

Tomcat 连接器配置:最大连接数(超过之后进入等待队列,和机器性能挂钩)、最大等待数(超过之后不再接收请求)

 

WebSocket(补充)

轮询与 Comet

HTTP 协议是一个请求 - 响应模式的协议,由客户端发起请求,服务端接收到请求从而给出响应。那么服务端是无法主动给客户端发送数据的。

为了解决这个问题,出现两种思路:

1、轮询:在客户端通过 js 脚本,每隔一段时间给服务端发送一个请求,询问服务端是否有新消息要发送。缺点:服务端的压力大,消息存在延迟。

2、Comet:本质上是一种异步的轮询,仍然存在缺点。

Ajax、Comet 与 Websocket

WebSocket

是 HTML5 新增的标准,让浏览器和服务器之间可以建立无限制的全双工通信,任何一方都可以主动发消息给对方。WebSocket 并不是全新的协议,而是利用 HTTP 协议来建立连接。

WebSocket 请求信息:

Tomcat 的 WebSocket 支持

Java WebSocket 中使用 Endpoint 对象代表 WebSocket 连接的一端,可以使用两种方式定义 Endpoint:

  1. 继承 javax.websocket.Endpoint  并实现其方法;
  2. 定义一个 POJO,并添加 @ServletEndpoint 相关注解。

Endpoint 实例在 WebSocket 握手时创建,并在客户端与服务端连接过程中有效。生命周期方法如下:

  • onOpen:当开启一个新的会话时调用(注解@OnOpen)
  • onClose:会话关闭时调用(注解@OnClose)
  • onError:连接过程中异常调用(注解 @OnError)

WebSocket简单介绍

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值