Tomcat 是个啥

前言

Tomcat 这个中间件对于 Web 开发者来说,人人皆知。大部分了解又不完全了解,甚至只是了解安装和配置 Catalina Home 环境变量。这个熟悉的陌生中间件,值得再稍微微深入学习一番。

Tomcat 是个啥

从 Servlet Demo 开始

最原始的 Java Web 开发,追溯到 10 年前,大部分还是在使用 Servlet + JSP 开发,开发完成打成 War 包,扔进 Tomcat webapps 文件夹,启动 Tomcat 即可运行。

一个简单例子如下。

1、web.xml 配置

<web-app>
    <display-name>Test Web Application</display-name>

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.lyqiang.learnjava.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

2、Servlet 类

/**
 * @author lyqiang
 */

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException 
{
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException 
{
        processRequest(request, response);
    }

    private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        printRespJsp(request, response);
    }

    private void printRespJsp(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        response.setContentType("text/html;charset=UTF-8");
        request.setAttribute("title""Hello");
        String content = "你好, 下次一定。<br/>你好, 下次一定。<br/>你好, 下次一定。<br/>";
        request.setAttribute("content", content);
        RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp");
        rd.forward(request, response);
    }

}

3、JSP 页面

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title><%=request.getAttribute("title")%>
    </title>
</head>
<body>
<h1><%=request.getAttribute("content")%>
</h1>
</body>
</html>

4、运行

访问 locahost:8080/hello

Tomcat 是个啥

Spring MVC 与 Spring Boot

Tomcat 是个啥

Spring MVC 框架的出现,在一定程度上简化了 Web 开发,并配合 FreeMarker、Thymeleaf 模版引擎更好地进行页面展现。Spring MVC 使用一个名为 DispatcherServlet 的 Servlet 处理所有的请求,开发者基于 @Controller@RequestMapping 注解就可以接受处理请求并返回结果。

<servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
@RequestMapping(value = "helloAbc", method = RequestMethod.GET)
    public Object hello(Model model) {

        CommentEntity comment = helloService.getCommentById(1);

        String content = "用户:" + comment.getUserName() + "<br/>" + "评论:" + comment.getContent() + "<br/>";
        model.addAttribute("title""Hi~");
        model.addAttribute("content", content);

        return "helloAbc";
    }

Spring MVC 的处理流程如下。

Tomcat 是个啥

后来 Spring Boot 的出现,更为激进地简化了 Java 后端的开发,对 Web 开发而言,甚至把 Tomcat 都集成内嵌了。

引入 spring-boot-starter-web 这个 starter 包就可以开始编写接口了,十分便捷。

从包的依赖关系上可以看到,它包含了 spring-webmvcspring-webspring-boot-starter-tomcat

Tomcat 是个啥


请求的流转

当在浏览器输入接口地址,敲击回车时发生了什么,如何流转到后台逻辑?

首先,浏览器需要先构造数据,然后发送 HTTP 请求,通过操作系统建立 TCP 连接,将数据发送出去;

以 linux 为例,操作系统底层通过 tcp_conect() 方法建立 TCP,但浏览器并不能直接使用操作系统底层的建立方式,而是操作系统提供一套 API 供应用程序调用,这个就是 Socket – 套接字 (这都 tm 什么神翻译)。

Tomcat 是个啥

服务端,Tomcat 通过 JDK 提供的 Socket 接口,与操作系统交互,创建 TCP 连接,保持监听,将接收的数据包,进行解析,封装成 Request, 传递给容器 (Engine -> Host -> Context -> Wrapper -> FilterChain -> Servlet),创建对应 Servlet 实例,并调用 service() 方法,执行业务逻辑。

javax.servlet.http.HttpServlet.service() 方法其实是根据不同类型的请求,调用了不同的实现方法。

Tomcat 是个啥


Tomcat 组件

从上述的大致流程可以概括出,

Tomcat 的作用是作为 Servlet 容器,接收 HTTP 请求,转换成 ServletRequest ,并按照映射关系创建 Servlet 实例,并执行方法。

Tomcat 官网架构介绍:https://tomcat.apache.org/tomcat-8.5-doc/architecture/overview.html

Tomcat 是个啥

Tomcat 内部分了不同的组件,和 server.xml 中的层级关系是一一对应的。

<Server>
  <Service>
    <Connector>
    </Connector>
    <Engine>  
     <Host>
        <Context>
        </Context>
     </Host>
    </Engine>
  </Service>
</Server>

Server

Server 元素在最顶层,代表整个 Tomcat 容器,一个 Server 元素中可以有一个或多个 Service 元素。

Service

ServiceConnectorEngine 外面包了一层,把它们组装在一起对外提供服务。一个 Service 可以包含多个 Connector,但是只能包含一个 EngineConnector 的作用是从客户端接收请求,Engine 的作用是处理接收进来的请求。

Connector

Connector 主要的职责就是接收客户端连接并接收消息报文,消息报文经由它解析后送往容器中处理。因为存在不同的通信协议,例如 HTTP 协议、AJP 协议等,所以需要不同的 Connector 组件,每种协议对应一个 Connector 组件,目前 Tomcat 包含 HTTP 和 AJP 两种协议的 Connector

Engine

EngineService 中的请求处理组件,从一个或多个 Connector 中接收请求并处理,并将完成的响应返回给 Connector,最终传递给客户端。

Host

HostEngine 的子容器, Engine 组件中可以内嵌 1 个或多个 Host 组件,每个 Host是一个虚拟主机。虚拟主机的作用是运行多个 Web 应用(一个 Context 代表一个 Web 应用),并负责安装、启动和结束每个 Web 应用。Tomcat 从 HTTP 头中提取出主机名,寻找名称匹配的主机。如果没有匹配,请求将发送至默认主机。

Context

ContextHost 的子容器,每个 Host 中可以定义任意多的 Context 元素。Context 元素代表在特定虚拟主机上运行的一个 Web 应用,Web 应用对应的是一个 WAR 文件,或 WAR 文件解压后的目录。

Tomcat 内部如何流转

Tomcat 是个啥

    1. 当 Tomcat 启动后,Connector 组件的接收器(Acceptor)将会监听是否有客户端套接字连接并接收 Socket

    2. 一旦监听到客户端连接,则将连接交由线程池 Executor 处理,开始执行请求响应任务。

    3. Http11Processor 组件负责从客户端连接中读取消息报文,然后开始解析 HTTP 的请求行、请求头部、请求体,将解析后的报文封装成 Request 对象。

    4. Mapper 组件根据 HTTP 协议请求行的 URL 属性值和请求头部的 Host 属性值匹配由哪个 Host 容器、 Context 容器、Wrapper 容器处理请求,这个过程其实就是根据请求从 Tomcat 中找到对应的 Servlet,然后将路由的结果封装到 Request 对象中,后续通过 Request 对象选择容器。

    5. CoyoteAdaptor 组件负责将 Connector 组件和 Engine 容器连接起来,把前面处理过程中生成的请求对象 Request 和响应对象 Response 传递到 Engine 容器,调用它的管道。

    6. Engine 容器的管道开始处理请求,管道里包含若干阀门(Valve),每个阀门负责某些处理逻辑。

    7. Host 容器的管道开始处理请求,它同样也包含若干阀门,首先执行这些阀门,然后执行基础阀门 HostValve,它继续往下调用 Context 容器的管道。

    8. Context 容器的管道开始处理请求,首先执行若干阀门,然后执行基础阀门 ContextValve,它负责调用 Wrapper 容器的管道。

    9. Wrapper 容器的管道开始处理请求,首先执行若干阀门,然后执行基础阀门 WrapperValve,它会执行该 Wrapper 容器对应的 Servlet 对象的处理方法,包括 init()service() 方法对请求进行逻辑处理,并将结果输出到客户端。

总结

目前最流行的 Web 服务器当属 Tomcat、Jetty、Undertow,它们都对 Servlet 规范进行了支持,为 Java 程序提供 Web 容器,各有优劣。

相比较而言 Tomcat 更重量级,以多级容器为基础构建,设计更复杂,以应对多场景的使用。更深入细节的内容需要阅读 Tomcat 的源码一探究竟了。

Tomcat 是个啥


关注一下,不迷路。


原文始发于微信公众号(郭儿的跋涉):Tomcat 是个啥

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35474.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!