27-Servlet执行原理

news2025/1/11 15:52:42

目录

1.Tomcat详解

①接收请求:

②根据请求计算响应:

③返回响应:

2.Tomcat执行流程

2.1.Tomcat 初始化流程

2.2.Tomcat 处理请求流程

2.3.Servlet 的 service 方法的实现


在 Servlet 的代码中并没有写 main ⽅法,那么对应的 doGet 代码是如何被调⽤的呢? 响应⼜是如何返回给浏览器的?这就要从 Tomcat 说起了。

1.Tomcat详解

我们⾃⼰的实现是在 Tomcat 基础上运⾏的。

当浏览器给服务器发送请求的时候,Tomcat 作为 HTTP 服务器,就可以接收到这个请求。HTTP 协议作为⼀个应⽤层协议,需要底层协议栈来⽀持⼯作:

更详细的交互过程:

①接收请求:

  • ⽤户在浏览器输⼊⼀个 URL,此时浏览器就会构造⼀个 HTTP 请求。
  • 这个 HTTP 请求会经过⽹络协议栈逐层进⾏封装成⼆进制的 bit 流,最终通过物理层的硬件设备转换成光信号/电信号传输出去。
  • 这些承载信息的光信号/电信号通过互联⽹上的⼀系列⽹络设备,最终到达⽬标主机(这个过程也需要⽹络层和数据链路层参与)。
  • 服务器主机收到这些光信号/电信号,⼜会通过⽹络协议栈逐层进⾏分⽤,层层解析,最终还原成 HTTP 请求。并交给 Tomcat 进程进⾏处理(根据端⼝号确定进程)。
  • Tomcat 通过 Socket 读取到这个请求(⼀个字符串),并按照 HTTP 请求的格式来解析这个请求,根据请求中的 Context Path 确定⼀个 webapp,再通过 Servlet Path 确定⼀个具体的类。再根据当前请求的⽅法 (GET/POST/...),决定调⽤这个类的 doGet 或者 doPost 等⽅法。此时我们的代码中的 doGet / doPost ⽅法的第⼀个参数 HttpServletRequest 就包含了这个 HTTP 请求的详细信息。

②根据请求计算响应:

  • 在我们的 doGet / doPost ⽅法中,就执⾏到了我们⾃⼰的代码。我们⾃⼰的代码会根据请求中的⼀些信息,来给 HttpServletResponse 对象设置⼀些属性,例如状态码,header,body 等。

③返回响应:

  • 我们的 doGet / doPost 执⾏完毕后,Tomcat 就会⾃动把 HttpServletResponse 这个我们刚设置好的对象转换成⼀个符合 HTTP 协议的字符串,通过 Socket 把这个响应发送出去。
  • 此时响应数据在服务器的主机上通过⽹络协议栈层层封装,最终⼜得到⼀个⼆进制的 bit 流,通过物理层硬件设备转换成光信号/电信号传输出去。
  • 这些承载信息的光信号/电信号通过互联⽹上的⼀系列⽹络设备,最终到达浏览器所在的主机(这个过 程也需要⽹络层和数据链路层参与)。
  • 浏览器主机收到这些光信号/电信号,⼜会通过⽹络协议栈逐层进⾏分⽤,层层解析,最终还原成 HTTP 响应,并交给浏览器处理。
  • 浏览器也通过 Socket 读到这个响应(⼀个字符串),按照 HTTP 响应的格式来解析这个响应,并且把body 中的数据按照⼀定的格式显示在浏览器的界⾯上。

2.Tomcat执行流程

下⾯的代码通过 "伪代码" 的形式描述了 Tomcat 的"初始化"/"处理请求"两部分核⼼逻辑。

所谓 "伪代码",并不是⼀些语法严谨,功能完备的代码,只是通过这种形式来⼤概表达某种逻辑。

2.1.Tomcat 初始化流程

class Tomcat {
    // ⽤来存储所有的 Servlet 对象
    private List<Servlet> instanceList = new ArrayList<>();
    
    public static void main(String[] args) {
        new Tomcat().start();
    }

    public void start() {
        // 根据约定,读取 WEB-INF/web.xml 配置⽂件,并解析被 @WebServlet 注解修饰的类
        // 假定这个数组⾥就包含了我们解析到的所有被 @WebServlet 注解修饰的类
        Class<Servlet>[] allServletClasses = ...
        // 这⾥要做的的是实例化出所有的 Servlet 对象出来
        for (Class<Servlet> cls : allServletClasses) {
            // 这⾥是利⽤ java 中的反射特性做的
            // 实际上还得涉及⼀个类的加载问题,因为我们的类字节码⽂件,是按照约定的⽅式(全部在WEB-INF/classes ⽂件夹下)存放的,所以 tomcat 内部是实现了⼀个⾃定义的类加载器(ClassLoader)⽤来负责这部分⼯作
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
        }

        //开始方法
        // 调⽤每个 Servlet 对象的 init() ⽅法,这个⽅法在对象的⽣命中只会被调⽤这⼀次
        for (Servlet ins : instanceList) {
            ins.init();
        }

        // 利⽤我们之前学过的知识,启动⼀个 HTTP 服务器
        // 并⽤线程池的⽅式分别处理每⼀个 Request
        ServerSocket serverSocket = new ServerSocket(8080); //开启一个web服务并设置端口号,监测:若有人访问此ip+端口,是能感知到的
        // 实际上 tomcat 不是⽤的固定线程池,这⾥只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);

        //多次拦截调用方法
        while (true) { //死循环,一直等待别人去访问
            Socket socket = ServerSocket.accept(); //如果没有人访问,就会阻塞到这行代码;如果有人访问,就会拿到请求的信息,往下执行
            // 每个请求都是⽤⼀个线程独⽴⽀持,这⾥体现了我们 Servlet 是运⾏在多线程环境下的
            pool.execute(new Runnable() {
                doHttpRequest(socket); //包含了一系列method方法
            });
        }

        //销毁方法
        // 调⽤每个 Servlet 对象的 destroy() ⽅法,这个⽅法在对象的⽣命中只会被调⽤这⼀次
        for (Servlet ins : instanceList) {
            ins.destroy();
        }
    }
}

小结:

  • Tomcat 的代码中内置了 main ⽅法,当我们启动 Tomcat 的时候,就是从 Tomcat 的 main ⽅法开始执⾏的。
  • 被 @WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取到,并集中管理。
  • Tomcat 通过反射这样的语法机制来创建被 @WebServlet 注解修饰的类的实例。
  • 这些实例被创建完了之后,会点调⽤其中的 init ⽅法进⾏初始化。(这个⽅法是 HttpServlet ⾃带的,我们⾃⼰写的类可以重写 init)
  • 这些实例被销毁之前,会调⽤其中的 destory ⽅法进⾏收尾⼯作。(这个⽅法是 HttpServlet ⾃带的,我 们⾃⼰写的类可以重写 destory)
  • Tomcat 内部也是通过 Socket API 进⾏⽹络通信。
  • Tomcat 为了能同时相应多个 HTTP 请求,采取了多线程的⽅式实现。因此 Servlet 是运⾏在多线程环境下的。

2.2.Tomcat 处理请求流程

class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进⾏ HTTP 协议的请求解析,和响应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        // 判断 URL 对应的⽂件是否可以直接在我们的根路径上找到对应的⽂件,如果找到,就是静态内容
        // 直接使⽤我们学习过的 IO 进⾏内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
        }
        // ⾛到这⾥的逻辑都是动态内容了
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        // 调⽤ Servlet 对象的 service ⽅法
        // 这⾥就会最终调⽤到我们⾃⼰写的 HttpServlet 的⼦类⾥的⽅法了
        try {
            ins.service(req, resp);    
        } catch (Exception e) {
            // 返回 500 ⻚⾯,表示服务器内部错误
        }
    }
}

小结:

  • Tomcat 从 Socket 中读到的 HTTP 请求是⼀个字符串,然后会按照 HTTP 协议的格式解析成⼀个 HttpServletRequest 对象。
  • Tomcat 会根据 URL 中的 path 判定这个请求是请求⼀个静态资源还是动态资源,如果是静态资源,直接找到对应的⽂件,把⽂件的内容通过 Socket 返回。如果是动态资源,才会执⾏到 Servlet 的相关逻辑。
  • Tomcat 会根据 URL 中的 Context Path 和 Servlet Path 确定要调⽤哪个 Servlet 实例的 service ⽅法。
  • 通过 service ⽅法,就会进⼀步调⽤到我们之前写的 doGet 或者 doPost。

2.3.Servlet 的 service 方法的实现

class Servlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, resp);
        } else if (method.equals("POST")) {
            doPost(req, resp);
       } else if (method.equals("PUT")) {
            doPut(req, resp);
       } else if (method.equals("DELETE")) {
            doDelete(req, resp);
       }
       ......
    }
}

小结:

  • Servlet 的 service ⽅法内部会根据当前请求的⽅法,决定调⽤其中的某个 doXXX ⽅法。
  • 在调⽤ doXXX ⽅法的时候,就会触发多态机制,从⽽执⾏到我们⾃⼰写的⼦类中的 doXXX ⽅法。

理解此处的多态

  • 我们⾃⼰写的 HelloServlet 类,继承⾃ HttpServlet 类,⽽ HttpServlet ⼜继承⾃ Servlet,相当于 HelloServlet 就是 Servlet 的⼦类。
  • 接下来,在 Tomcat 启动阶段,Tomcat 已经根据注解的描述,创建了 HelloServlet 的实例,然后把这个实例放到了Servlet 数组中。
  • 后⾯我们根据请求的 URL 从数组中获取到了该 HelloServlet 实例,但是我们是通过 Servlet ins 这 样的⽗类引⽤来获取到 HelloServlet 实例的。
  • 最后,我们通过 ins.doGet() 这样的代码调⽤ doGet 的时候,正是 "⽗类引⽤指向⼦类对象",此时就会触发多态机制,从⽽调⽤到我们之前在 HelloServlet 中所实现的 doGet ⽅法。

等价代码:

Servlet ins = new HelloServlet();
ins.doGet(req, resp);

小结:

①Tomcat的main方法

启动Socket网络编程->得到所有请求

②Tomcat的doHttpRequest方法

url->@WebServlet类

Servlet->service(req, resp)

③Servlet的service方法

得到方法类型。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/460878.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022年中国预制菜市场规模已超过4000亿元,2026年将突破万亿

佛跳墙、小酥肉、酸菜鱼、猪肚鸡、煎牛排、炸鸡、小龙虾等等&#xff0c;这些需要花上长时间烹饪制作的大菜&#xff0c;现在只需用烤箱或空气炸锅几分钟就制作出来了&#xff0c;且味道还不赖。预制菜最大的优势在于方便&#xff0c;极大的省去了买菜洗菜、切菜、制作的繁琐程…

YOLOv5网络模型的结构原理讲解(全)

目录 前言1. 基本概念2. 输入端2.1 Mosaic 图像增强2.2 自适应锚框计算2.3 自适应图片缩放 3. Backbone层3.1 Focus结构3.2 CSP结构 3. Neck网络3.1 SPP结构3.2 PAN结构 4. 输出端4.1 Bounding box损失函数4.2 NMS非极大值抑制 前言 YOLOv5有几种不同的架构&#xff0c;各网络…

ChatGPT评微博热文“留给普通人的最后一扇门,快要关闭了”

目录 留给普通人的最后一扇门&#xff0c;快要关闭了 这篇文章你看过吗 普通人通过接受高等教育提升阶级的路还走得通吗&#xff0c;为什么大家都开始考公务员了 高等教育仍然是提升阶级的一条途径&#xff0c;但并不是唯一的途径。那还有哪些路径&#xff1f; 继续&#x…

【谷歌插件开发】获取当前网站COOKIE并上报HTTP-API

一 背景 由于本人每天需要登录网站查看数据并分析统计汇总&#xff0c;而每次机械式地搜索和简单计算&#xff0c;十分繁琐。我们可以写个定时任务&#xff0c;每天根据cookie获取网站数据并遍历统计。 脚本得以成功执行的关键是需要获取到COOKIE 故&#xff0c;写了个谷歌插件…

UE4架构初识(七)

目录 UE4仿真引擎学习 一、架构基础总结 1. 游戏世界 2. 数据和逻辑 3. 整体类图 UE4仿真引擎学习 一、架构基础总结 1. 游戏世界 在UE的眼里&#xff0c;游戏世界的万物皆Actor&#xff0c;Actor再通过Component组装功能。Actor又通过UChildActorComponent实现Actor之间的…

代码随想录之贪心合集

455 分发饼干 先排序之后按顺序比较 class Solution {public int findContentChildren(int[] g, int[] s) {//57Arrays.sort(g);Arrays.sort(s);int k0;int i0;int count0;while(k<s.length&&i<g.length){if(g[i]<s[k]){count;i;k;}else k;}return count;} }…

视频大文件传输的演变:从“卷轴男孩”到自动化

200年前&#xff0c;从纽约市到英国伦敦的单程旅行需要乘坐一艘跨大西洋轮船将近三周——如果你能负担得起的话&#xff0c;那就是。那些不能在满是汗水、狭窄的帆船上安顿大约一个半月的人。 今天&#xff0c;视频专业人士能够在几小时甚至几分钟内跨越相同的物理距离传输大量…

烟雾弹?突然转变?如何看待微软发声:中国是主要的对手

是的&#xff0c;我又回来了&#xff0c;今天要跟各位唠的还是ChatGPT的嗑。今天的新闻是啥呢&#xff1f; 《微软总裁&#xff1a;中国将是 ChatGPT 的主要对手&#xff0c;我们的优势不大》 说实话&#xff0c;我看到这个新闻的时候&#xff0c;大感震撼&#xff0c;在相关报…

YOLOv5快速入门demo

文章目录 1. 官网下载 yolo_master2. 下载得到yolov5-maser.zip 对其进行解压3. 安装所需要的包4. 官网下载一个与训练模型5. 测试一个小demo 使用detect.py6. 训练一个模型 1. 官网下载 yolo_master https://gitcode.net/mirrors/ultralytics/yolov5 下载克隆 2. 下载得到…

HART协议数据格式避坑(C语言压缩字符串Packed-ASCII和ASCII转换)

HART协议数据格式避坑&#xff08;C语言压缩字符串Packed-ASCII和ASCII转换&#xff09; 首先HART数据格式如下&#xff1a; 重点就是浮点数和字符串类型 Latin-1就不说了 基本用不到 浮点数 浮点数里面 如 0x40 80 00 00表示4.0f 在HART协议里面 浮点数是按大端格式发送的…

oracle 18c dataguard 从库scn 不更新BUG

Bug 29056767 - STANDBY: Datafiles Checkpoint not Updated at Standby Database when Media Recover is running (Doc ID 29056767.8)正在上传…重新上传取消To Bottom Bug 29056767 STANDBY: Datafiles Checkpoint not Updated at Standby Database when Media Recover i…

IPEmotion控制模块-PID循环应用

IPEmotion专业版、开发版支持控制模块&#xff0c;并且该模块支持函数发生器、PID控制器、路由器、序列控制和序列控制块以及参考曲线生成器。本文主要针对PID&#xff08;P&#xff1a;Proportional control 比例控制&#xff1b;I&#xff1a;Integral control 积分控制&…

Linux tail 命令

前言 Linux 实时查看日志文件&#xff0c;最主要使用的就是tail命令。 linux tail命令用于显示文件尾部的内容&#xff0c;默认在屏幕上显示指定文件的末尾10行。如果给定的文件不止一个&#xff0c;则在显示的每个文件前面加一个文件名标题。如果没有指定文件或者文件名为“-”…

同步辐射全散射PDF分析:探究材料结构的新方法

同步辐射全散射PDF&#xff08;Pair Distribution Function&#xff09;分析是一种非常强大的物质结构研究方法。它通过同步辐射技术&#xff0c;将X射线或中子散射的数据进行处理&#xff0c;得到物质的原子间距分布函数&#xff0c;从而揭示物质的微观结构信息。该方法已经在…

Vue3上传(Upload)

可自定义设置以下属性&#xff1a; 接受上传的文件类型&#xff08;accept&#xff09;&#xff0c;类型&#xff1a;string&#xff0c;默认 *&#xff0c;&#xff0c;与<input type"file">的accept属性一致&#xff0c;详见 https://developer.mozilla.org/…

数据结构与算法(五):算法专项 Hash、BitMap、Set、布隆过滤器、中文分词、Lucene 倒排索引

算法专项 Hash、BitMap、Set、布隆过滤器、中文分词、Lucene 倒排索引 Hash 思考&#xff1a; 给你N&#xff08;1<N<10&#xff09;个自然数,每个数的范围为&#xff08;1~100&#xff09;。现在让你以最快的速度判断某一个数是否在这N个数内&#xff0c;不得使用已经…

Ubuntu20.04+安装MySQL8+ 并设置忽略表名大小写

更新apt apt -y update安装mysql-server apt -y install mysql-server查看服务是否启动 ps -ef | grep mysql如下图启动成功 或者 systemctl status mysql设置root登录密码 执行命令&#xff1a; mysql -uroot选择数据库&#xff1a; use mysql;修改密码&#xff1a; a…

0602基础使用(一)-react路由-react

文章目录 1 基本使用1.1 安装js库1.2 使用示例1.3 总结 2 路由组件与一般组件2.1 路由组件2.2 路由组件与普通组件示例2.3 总结 3 NavLink组件3.1 NavLink 简介3.2 NavLink实现高亮与自定义样式 结语 1 基本使用 1.1 安装js库 react-router-dom&#xff0c;react的一个插件库…

flink on k8s提交任务

目录 相关文档前置准备构建镜像提交任务 相关文档 https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/resource-providers/native_kubernetes/ 前置准备 flink的lib目录下放入两个依赖 bcpkix-jdk15on-1.68.jar bcprov-jdk15on-1.69.jar 创建用户…

Vue过滤器的基本使用

过滤器 功能&#xff1a;对要显示的数据进行特定格式化后再显示 注意&#xff1a;并没有改变原本的数据&#xff0c;是产生新的对应的数据 声明&#xff1a;过滤器不是必须要用到的东西&#xff0c;而是vue提供处理数据的方式而已&#xff0c;想用就用&#xff0c;不想用可以…