Servlet的详解

news2024/11/20 4:52:22

Servlet 的主要工作


允许程序员注册一个类,在 Tomcat 收到的某个特定的 HTTP 请求的时候,执行这个类中的一些代码
帮助程序员解析 HTTP 请求,把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象
帮助程序员构造 HTTP 响应,程序员只要给指定的 HttpResponse 对象填写一些属性字段,Servlet 就会自动的按照 HTTP 协议的方式构造出一个 HTTP 响应字符串,并通过 Socket 编写返回给客户端
一般的servlet

MySelfServlet =============extend====》HttpServlet

    ==============》GenericServlet

=============》Servlet

public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String user = req.getParameter("user");
    }
}

HttpServletRequest: 表示 HTTP 请求,Tomcat 按照 HTTP 请求的的格式把字符串格式的请求转换成了一个 HttpServletRequest 对象,通过这个对象就可以获取请求中的信息
HttpServletResponse: 表示 HTTP 响应,通过代码可以把响应的对象构造好,然后 Tomcat 将响应返回给浏览器
通过 doGet 的源码我们可以大致了解,它的作用是根据收到的请求通过响应返回一个 405 或者 400,那么我们可以重写这个方法,根据收到的请求执行自己的业务逻辑,把结果构造成响应对象
 

在 doGet 方法中,通过 HttpServletResponse 类的 getWriter() 方法往响应的 body 中写入文本格式数据

@WebServlet("/test")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String user = req.getParameter("user");
        
        resp.getWriter().write("aa");
    }
}

Servlet 运行原理


在 Servlet 的代码中,我们并没有写 main 方法,那么对应的 doGet 代码是如何被调用呢?响应又是如何返回给浏览器的呢?

Servlet 的架构
我们自己实现的 Servlet 是在 Tomcat 基础上运行的

当浏览器给服务器发送请求时,Tomcat 作为 HTTP 服务器,就可以接收到这个请求。Tomcat 的工作就是解析 HTTP 请求,并把请求交给 Servlet 的代码来进行进一步的处理。Servlet 的代码根据请求计算生成响应对象,Tomcat 再把这个响应对象构造成 HTTP 响应,返回给浏览器。并且 Servlet 的代码也经常会和数据库进行数据的传递。

 Tomcat 的伪代码
下面通过 Tomcat 的伪代码的形式来描述 Tomcat 初始化和处理请求两部分核心逻辑

Tomcat 的初始化流程

class Tomcat {

    // 用来存储所有的 Servlet 对象
    private List<Servlet> instanceList = new ArrayList<>();
    
    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);
        // 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是用一个线程独立支持,这里体现了 Servlet 是运行在多线程环境下的
            pool.execute(new Runnable() {
                doHttpRequest(socket);
            });
        }
        // 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次
        for (Servlet ins : instanceList) {
            ins.destroy();
        }
    }
    
    public static void main(String[] args) {
        new Tomcat().start();
    }
}

Tomcat 的代码内置了 main 方法,当我们启动 Tomcat 的时候,就是从 Tomcat 的 main 方法开始执行的
被 @WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取到,并集中管理
Tomcat 通过反射这样的语法机制来创建被 @WebServlet 注解修饰的类的实例
这些实例被创建完之后,就会调用其中的 init 方法进行初始化
这些实例被销毁之前,就会调用其中的 destory 方法进行收尾工作
Tomcat 内部也是通过 Socket API 进行网络通信
Tomcat 为了能够同时处理多个 HTTP 请求,采取了多线程的方式实现,因此 Servlet 是运行在多线程环境下的。

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;
        }
        
        // 走到这里的逻辑都是动态内容了
        // 找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        
        // 调用 Servlet 对象的 service 方法
        // 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了
        try {
        	ins.service(req, resp);
        } catch (Exception e) {
        	// 返回 500 页面,表示服务器内部错误
        }
    }
}

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

Servlet API 详解
对于 Servlet 主要介绍三个类,分别是 HttpServlet、HttpServletRequest 和 HttpServletResponse。

其中 HttpServletRequest 和 HttpServletResponse 是 Servlet 规范中规定的两个接口,HttpServlet 中并没有实现这两个接口的成员变量,它们只是 HttpServlet 的 service 和 doXXX 等方法的参数。这两个接口类的实例化是在 Servlet 容器中实现的。

HttpServlet

 

Servlet 的生命周期: Servlet 的生命周期就是 Servlet 对象从创建到销毁的过程,下面来介绍其生命周期的过程

Servlet 对象是由 Tomcat 来进行实例化的,并且在实例化完毕之后调用 init 方法(只调用一次)
Tomcat 对于收到的请求,都会通过对应的 Servlet 的 service 方法来进行处理(可以调用多次)
Tomcat 在结束之前,会调用 Servlet 的 destory 方法来进行回收资源(最多调用一次)
注意: init 和 service 能够保证在各自的合适时机被 Tomcat 调用,但是 destory 不一定,它是否能够被调用取决于 Tomcat 是如何结束的

如果直接杀死进程,那么就来不及调用 destory
如果通过 Tomcat 的管理端口(默认 8005)进行关闭,就能够调用 destory

HttpServletRequest

 HttpServletResponse

 

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

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

相关文章

用 CSS 自定义滚动条

简介 首先需要介绍一下滚动条的组成部分。滚动条包含 track 和 thumb&#xff0c;如下图所示&#xff1a; track是滚动条的基础&#xff0c;其中的 thumb是用户拖动支页面或章节内的滚动。 案例&#xff1a; 案例代码&#xff1a; <!DOCTYPE html> <html><he…

python 递归下降分析法的设计与实验原理 编译原理

本文内容&#xff1a; 本文章实现的文法&#xff1a; E->T|ET; T->F|T*F; F->i|(E);利用上一篇文章&#xff1a;python 预备实验2 LL(1)文法构造转化后的输出&#xff1a; E->TE; T->FT; F->i|(E); E->TE|; T->*FT|; 手工测试&#xff0c;是LL(1)文…

Flink+Pulsar、Kafka问题分析及方案 -- 事务阻塞

Pulsar、Kafka的事务设计 Pulsar跟Kafka在设计事务功能时&#xff0c;在消费者读取消息的顺序方面&#xff0c;都采用了类似的设计。 比如说&#xff0c;先创建txn1&#xff0c;然后创建txn2&#xff0c;这两个事务生产消息到同一个topic/partition里&#xff0c;但是txn2比tx…

【前端知识】常见的加密算法介绍

【前端知识】常见的加密算法介绍 1 常见的加密算法&#xff08;1&#xff09;哈希函数&#xff08;2&#xff09;对称加密&#xff08;3&#xff09;非对称加密&#xff08;4&#xff09;消息认证码&#xff08;MAC&#xff09; 2.总结 1 常见的加密算法 略微介绍一下前端中常…

Kerberos

序言 kerberos 除了说帮我们验证Java程序是否具有权限来请求Hadoop的服务,也可以来帮助我们检查新增的节点是是否是真实的节点,还是黑客为了套取数据的节点. 比如为HDFS新增一个DataNode节点,如果没有Kerberos验证, 随便一个节点只要连接上NameNode就会存储数据,黑客就可以获…

LeetCode:23. 合并 K 个升序链表

23. 合并 K 个升序链表 1&#xff09;题目2&#xff09;过程3&#xff09;代码1. 最开始2.初步优化 4&#xff09;结果1. 最开始2. 初步优化 1&#xff09;题目 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合…

机器学习基础认识(一)

机器学习应用 机器学习的应用&#xff0c;主要分为两类&#xff1a;预测、分类 预测&#xff0c;一般是指&#xff1a;根据数据&#xff0c;预测数值 分类&#xff0c;一般是指&#xff1a;根据数据&#xff0c;进行分类 预测与分类的关系【个人理解】 分类&#xff0c;本质…

零基础怎么入门网络安全?看这篇就够啦!

由于我之前写了不少网络安全技术相关的故事文章&#xff0c;不少读者朋友知道我是从事网络安全相关的工作&#xff0c;于是经常有人在微信里问我&#xff1a; 我刚入门网络安全&#xff0c;该怎么学&#xff1f;要学哪些东西&#xff1f;有哪些方向&#xff1f;怎么选&#xff…

Centos7.6部署postgresql15主从

目录 安装pg15&#xff08;master和standby&#xff09;主数据库配置(master)初始化数据库创建归档日志目录设置数据库访问权限修改数据库配置文件开启数据库 从数据库配置(standby)同步主库的数据文件创建文件standby.signal启动从数据库 主从状态验证master上验证standby上验…

H5性能测试怎么做?这些关键指标你得搞清楚

目录 01、Http相关 02、组件是否压缩 03、图片格式和大小是否合适 04、CSS放在顶部 05、JS放在底部 06、JS &CSS压缩 07、是否添加缓存 08、避免非200返回值 09、使用CDN 03、WebView相关 学习资源分享 软件测试面试小程序 01、Http相关 01、Http请求个数 有…

新星计划 Electron+vue2 桌面应用 1 基础

/(ㄒoㄒ)/~~报名了两个新星计划&#xff0c;工作之余写博客…… 另外一个是uniapp的属于个人兴趣&#xff0c;这个桌面应用正好符合工作需要。 活动地址&#xff1a;https://marketing.csdn.net/p/1738cda78d47b2ebb920916aab7c3584 教程地址&#xff1a; 2023新星导师活动…

Java实现PDF导出/预览

网上有很多关于PDF导出的文章&#xff0c;但是个人感觉实现的过于复杂&#xff0c;又是模板又是html的&#xff0c;有的还需要字体模板的支持&#xff0c;本片文章只是实现简单的PDF表格导出&#xff0c;可以实现PDF动态表格导出/预览&#xff0c;这类文章网上很少&#xff0c;…

实践「容器镜像扫描」,Get 云原生应用的正确打开方式

&#x1f31f; 容器技术的兴起&#xff0c;让应用程序更加轻量化和可移植&#xff0c;大大提高了应用交付效率。但容器中的应用也面临各种安全威胁&#xff0c;容器及其镜像安全不可小觑。 近日&#xff0c;在「DevSecOps 软件安全开发实践」课程上&#xff0c;极狐(GitLab) 高…

Linux设置系统时间(上海时区、硬件时间、重启有效)

#查看时间 date#删除当前时区 rm -rf /etc/localtime #修改默认时区为上海 ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #设置硬件时间 月/日/年 时:分:秒 hwclock --set --date"05/18/2023 17:11:15"#设置系统时间和硬件时间同步 hwclock --hctosys#保…

大数据发展前沿复习

对抗学习 生成对抗网络&#xff08;GAN&#xff09;是非监督式学习的一种方法&#xff0c;透过两个神经网络相互博弈的方式进行学习。生成对抗网络由一个生成网络与一个判别网络组成。生成网络以随机取样作为输入&#xff0c;其输出结果需要尽量模仿训练集中的真实样本。判别网…

vmware17pro安装激活ubuntu22版本最新教程无废话

第一步&#xff1a;下载 下载很方便 官方一键下载链接 第二步 安装 点下一步&#xff0c;一键安装即可&#xff0c;有可能会重启电脑&#xff0c;没关系的&#xff0c;是安全的 第三步&#xff1a;ji活 懂得都懂这是什么 JU090-6039P-08409-8J0QH-2YR7F 4A4RR-813DK-M81A9…

C语言算法--快速排序法

C语言算法–快速排序法 1-什么是快速排序法 快速排序&#xff08;Quicksort&#xff09;是一种常用的排序算法&#xff0c;它基于分治的思想。它的核心思想是选择一个基准元素&#xff0c;将数组划分为两个子数组&#xff0c;使得左边的子数组中的所有元素都小于等于基准元素…

【Flutter开发】Navigator2.0介绍及使用

目录 Navigator1.0Navigator2.0APPRouteInformationParserRouterDelegate 问题The Navigator.pages must not be empty to use the Navigator.pages API浏览器的回退按钮 总结 Navigator1.0 我们学习flutter一开始接触的路由管理就是Navigator1.0&#xff0c;它非常方便&#…

JAVA-Activiti 7与达梦、人大金仓兼容-nacos、服务pom文件配置(2)

目录 第一步,修改nacos服务配置 >需注意< 第二步,pom.xml依赖包配置 Activiti的源码包解决之后,接下来就好做很多了 第一步,修改nacos服务配置 spring:datasource:url: jdbc:kingbase8://127.0.0.1:54321/progress?currentSchemaprogress,productNamePostgreSQL,SYS…

保密+完整+可用+安全,规避代码安全「马奇诺防线」,构建软件供应链整体安全

近日&#xff0c;在「江狐会」广州站上&#xff0c;极狐(GitLab) 高级解决方案架构师武让分享了如何通过三大阶段 四大要点&#xff0c;规避代码安全「马奇诺防线」&#xff0c;真正确保软件供应链安全。以下内容整理自本次演讲。Enjoy&#xff5e; 先跟大家分享一个故事 一战…