Servlet、Servlet的5个接口方法、生命周期、以及模拟实现 HttpServlet 来写接口的基本原理

news2025/4/21 3:16:26

DAY15.1 Java核心基础

Servlet

Servlet是一个接口,是java的基础,java之所以编写web的程序,接收请求并响应,就是因为Sevlet接口

Java 类实现了Servlet接口的时候就可以接收并响应请求,成为web服务器

Web服务器就是接收请求,然后处理并响应结果

代码示例:

创建一个HelloServlet,实现Servlet接口,实现它的方法

yes,需要先导入相关的包

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>
@WebServlet("/hello")
public class HelloServlet implements Servlet {
    /**
     * 初始化方法
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("执行了初始化方法");
    }

    /**
     * 配置方法 ,一般不用
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 业务方法
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("执行了业务方法");
    }

    /**
     * 获取Servlet的名称 ,一般不用
     * @return
     */
    @Override
    public String getServletInfo() {
        return "";
    }

    /**
     * 销毁方法
     */
    @Override
    public void destroy() {

    }
}

重要的实现方法:

  • public void init(ServletConfig servletConfig):第一次调用Servlet的时候执行,只执行一次
  • public void service(ServletRequest servletRequest, ServletResponse servletResponse):调用一次执行一次
  • public void destroy():关闭Tomcat 的时候执行一次

但是这些都是非静态方法,非静态方法调用的时候必须创建对象,才能使用这些方法

那么什么时候创建这个对象?如何创建这个对象呢?

是Tomcat通过反射的机制调用实现类的无参构造 动态创建的对象

要注意实现类的WebUrl映射不能设置为同样的url,不然Tomcat会报错,比如:

@WebServlet("/hello")
public class HelloServlet1 implements Servlet
@WebServlet("/hello")
public class HelloServlet2 implements Servlet

报错提示不能映射为同一个url模式

image-20250321153124779

首先创建了 HelloServlet 对象,调用了对象的 init 方法,调用了对象的 service 方法

Servlet 的生命周期:先有对象,初始化对象,调用对象的方法

当第一次访问 Servlet 的时候创建 Servlet 的实例化对象

Tomcat根据请求找到相应的Servlet实现类,是通过注解进行匹配的

Servlet是一个单例模式,一次创建多次调用

Servlet 的生命周期

当请求某个Servlet的时候,首先会创建Servlet这个对象的实例化对象(Tomcat通过反射机制创建),然后调用init方法进行初始化操作,然后调用service方法进行完成业务处理,当重复请求同一个Servlet的时候不会再次创建这个实例化对象,而是直接使用service方法完成业务操作,因为这个对象被Tomcat保存到了一个容器之中,然后在关闭Tomcat的时候会调用destory方法进行销毁

构造函数:只调用一次,在创建的时候

init方法:只调用一次,第一次创建的时候

service方法:多次重复调用,每次请求调用一次

destory犯法:只调用一次,在Tomcat关闭的时候调用

Servlet 接口中只有service方法经常使用,其它4个方法基本没用

如果每次实现的时候都需要实现5个方法,太麻烦了,代码太多了,如何解决呢?

可以用继承一个BaseServlet,然后后面直接继承这个基础类,只需要重写service方法即可

@WebServlet("/base")
public class BaseServlet implements Servlet {
    /**
     * 初始化方法
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("执行了初始化方法");
    }

    /**
     * 配置方法 ,一般不用
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 业务方法
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Base执行了业务方法");
    }

    /**
     * 获取Servlet的名称 ,一般不用
     * @return
     */
    @Override
    public String getServletInfo() {
        return "";
    }

    /**
     * 销毁方法
     */
    @Override
    public void destroy() {

    }
}

通过继承可以实现只实现service方法,不需要全部重写

@WebServlet("/test2")
public class TestServlet extends BaseServlet{
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("test2");
    }
}

启动Tomcat访问http://localhost:3030/test2,可以看见他调用了TestServlet的service方法

image-20250321201408920

站在父亲的肩膀上省事

但是在我们的日常使用中我们是不是只需要重写一个doGet方法和一个doPost方法就可以实现业务板块了呢,这个时候就需要将service的业务分类了,这边不细分,先写get和post方法的处理,那我们是写在实现类还是写在父类呢,当然是写在父类基础类呀,这样我们就不用管父类的分发工作了,我们只需要写一个get和post方法即可实现接收get和post请求,这样说着太空洞了,我们来代码展示:

基本类:BaseServlet(我们自己创建的父类)

小知识:

  • HttpServletRequest:ServletRequest的子类,内置多个可以获取到请求信息的函数
  • HttpServletResponse:ServletResponse的子类,可以封装信息通过HttpServletResponse的函数返回到浏览器
@WebServlet("/base")
public class BaseServlet implements Servlet {
    /**
     * 初始化方法
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("执行了初始化方法");
    }

    /**
     * 配置方法 ,一般不用
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 业务方法
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Base执行了业务方法");
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String method = httpServletRequest.getMethod();
        System.out.println("当前请求的方法:"+method);
        System.out.println("User-agent:"+httpServletRequest.getHeader("User-agent"));
        switch (method){
            case "GET":
                doGet(httpServletRequest,httpServletResponse);
                break;
            case "POST":
                doPost(httpServletRequest,httpServletResponse);
                break;
            default:
                System.out.println("不支持的请求方法");
                break;
        }
    }

    /**
     * 获取Servlet的名称 ,一般不用
     * @return
     */
    @Override
    public String getServletInfo() {
        return "";
    }

    /**
     * 销毁方法
     */
    @Override
    public void destroy() {

    }
    // 处理Get请求
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("调用了doGet方法");
    }
    // 处理Post请求
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("调用了doPost方法");
    }
}
  • 可以看见这个类实现了Servlet接口必须实现的5个接口
  • 然后这个类的service业务接口做了一个分类实现

测试类TestServlet:继承了基本类 BaseServlet,简化了代码

@WebServlet("/test2")
public class TestServlet extends BaseServlet{

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("重写的doPost方法");
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("重写的doGet方法");
    }
}

只需要重写一个doGet或者一个doPost方法就可以实现对应类型接口的业务实现了,这样开发者就可以着重到业务代码里面了

来看看Serlet方法常见的写网络接口的方式:

@WebServlet("/test")
public class Test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("GBK");
        resp.getWriter().write("Hello World,这是Tomcat!");
    }
}

可以看见他也是继承了一个HttpServlet类,然后实现了一个doGet方法就完成了,是不是感觉好像和上面有几分相似,哈哈哈,你自己体会体会

总结:

第一代 BaseServlet 实现 Servlet 接口,实现全部 5 个方法

第二代 TestServlet继承 BaseServlet,重写 service 方法

第三代开发者自定义的类继承 BaseServlet,重写 doGet 和 doPost 方法即可

  • 区分不同的请求类型,进行分发

  • 将 ServletRequest 和 ServletResponse 全部强转为子类类型 HttpServletRequest 和 HttpServletResponse

Servlet 的调用体系,通过继承的方式将原本的工作分层三层去完成,每一次都承担一些任务,最终来到开发者自定义这层之后,工作量会减少很多,因为其父类已经完成了其他的工作,只保留最核心的方法交由开发者自定义的类来实现,提高了开发效率,减少了代码量。

继承是 Java 中代码复用的重要应用之一,父类所做的工作,子类可以直接继承,就不需要额外再次去完成重复的工作了,提高代码的效率,开发效率。

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

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

相关文章

贝叶斯公式的一个直观解释

E E E&#xff1a;抓到娃娃 H H H&#xff1a;坐地铁 H ˉ \bar H Hˉ&#xff1a;坐公交 P ( E ) P ( H ) P ( E ∣ H ) P ( H ‾ ) P ( E ∣ H ‾ ) P({E}) P({H}) P({E} \mid {H}) {P}(\overline{{H}}) {P}({E} \mid \overline{{H}}) P(E)P(H)P(E∣H)P(H)P(E∣H) P (…

Java 大视界 -- Java 大数据分布式计算中的通信优化与网络拓扑设计(145)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

reconstruct_3d_object_model_for_matching例子

文章目录 1.获取om3文件2.准备可视化3.准备3D可视化4.读取3D模型5.显示成对注册结果16.显示成对注册结果27.联合注册模型8.处理图像8.1子采样8.2 图像计算与平滑8.3 三角测量 9.基于表面做3D匹配10.评估模型准确度10.1 在场景中找到模型10.2 计算模型和场景之间的距离 11.立体系…

【JavaWeb学习Day27】

Tlias前端 员工管理 条件分页查询&#xff1a; 页面布局 搜索栏&#xff1a; <!-- 搜索栏 --><div class"container"><el-form :inline"true" :model"searchEmp" class"demo-form-inline"><el-form-item label…

Webrtc编译官方示例实现视频通话

Webrtc编译官方示例实现视频通话 前言 webrtc官网demo中给了一个供我们学习和应用webrtc的一个很好的例子&#xff1a;peerconnection&#xff0c;这期我们就来编译和运行下这个程序看看视频通话的效果以。 1、打开源码工程 继上期源码编译完成后&#xff0c;我们使用vs打开…

大数据学习(80)-数仓分层

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

刘强东突然发声:不该用算法压榨最底层兄弟!东哥,真正的人民企业家

今天忙了一天&#xff0c;很累&#xff0c;准备睡觉的时候&#xff0c;看到网上盛传的刘强东的朋友圈&#xff0c;东哥又在朋友圈发文了。 说实话&#xff0c;看完之后&#xff0c;感动&#xff0c;真的感动。 尤其是当我看到这两句话的时候。 1、我们所学的知识、商业模式、技…

Java 记忆链表,LinkedList 的升级版

文章目录 记忆链表 MemoryLinkedList实战源代码 众所周知&#xff0c;ArrayList 和 LinkedList 是 Java 集合中两个基本的数据结构&#xff0c;对应数据结构理论中的数组和链表。但在这两个数据结构&#xff0c;开发者们通常使用 ArrayList&#xff0c;而不使用 LinkedList。JD…

poetry安装与使用

文章目录 安装方法创建虚拟环境其他常用命令从 poetry.lock 中安装第三方依赖包 安装方法 安装命令&#xff08;全局安装&#xff0c;不要在虚拟环境中安装&#xff0c;方便后面创建环境使用&#xff09; pip install poetry修改虚拟环境路径&#xff08;首次使用poetry时执行&…

UVM config机制及uvm_resource_pool

目录 1. uvm_config_db 类源码 1.1 set 1.2 get 2. uvm_resource_pool 2.1 uvm_resource_pool::set 2.2 uvm_resource 3. usage 4. 小结 uvm提供一种uvm_config_db机制使得在仿真中通过变量设置来修改环境,使环境更加灵活。本文主要介绍uvm_config_db#(type)::get/set…

JAVA学习*接口

接口 在生活中我们常听说USB接口&#xff0c;那接口是什么呢&#xff1f; 在Java中&#xff0c;接口相当于多个类的一种公共规范&#xff0c;是一种引用数据类型。 定义接口 public interface IUSB {public static final String SIZE "small";public abstract vo…

Python实验:读写文本文件并添加行号

[实验目的] 熟练掌握内置函数open()的用法&#xff1b;熟练运用内置函数len()、max()、和enumerate()&#xff1b;熟练运用字符串的strip()、ljust()和其它方法&#xff1b;熟练运用列表推导式。 [实验和内容] 1.编写一个程序demo.py&#xff0c;要求运行该程序后&#xff0…

IDEA导入jar包后提示无法解析jar包中的类,比如无法解析符号 ‘log4j‘

IDEA导入jar包后提示无法解析jar包中的类 问题描述解决方法 问题描述 IDEA导入jar包的Maven坐标后&#xff0c;使用jar中的类比如log4j&#xff0c;仍然提示比如无法解析符号 log4j。 解决方法 在添加了依赖和配置文件后&#xff0c;确保刷新你的IDE项目和任何缓存&#xff…

数据结构——顺序栈seq_stack

前言&#xff1a;大家好&#x1f60d;&#xff0c;本文主要介绍了数据结构——顺序栈 目录 一、概念 1.1 顺序栈的基本概念 1.2 顺序栈的存储结构 二、基本操作 2.1 结构体定义 2.2 初始化 2.3 判空 2.4 判满 2.5 扩容 2.6 插入 入栈 2.7 删除 出栈 2.8 获取栈顶元…

python3.13.2安装详细步骤(附安装包)

文章目录 前言一、python3.13.2下载二、python3.13.2安装详细步骤1.查看安装文件2.启动安装程序3.安装模式选择4.自定义安装配置5.高级选项设置6.执行安装7.开始安装8.安装完成8.打开软件9.安装验证 前言 在数字化时代&#xff0c;Python 已成为不可或缺的编程语言。无论是开发…

AI-Talk开发板之更换串口引脚

一、默认引脚 CSK6011A使用UART0作为Debug uart&#xff0c;AI-Talk开发板默认使用的GPIOA2和GPIOA3作为Debug uart的RX和TX&#xff0c;通过连接器CN6引出。 二 、更换到其它引脚 查看60xx_iomux_v1.0可以&#xff0c;UART0的tx和rx可以映射到很多管脚上。 结合AI-Talk开发板…

深度解读DeepSeek:源码解读 DeepSeek-V3

深度解读DeepSeek&#xff1a;开源周&#xff08;Open Source Week&#xff09;技术解读 深度解读DeepSeek&#xff1a;源码解读 DeepSeek-V3 深度解读DeepSeek&#xff1a;技术原理 深度解读DeepSeek&#xff1a;发展历程 文章目录 整体流程模型初始化模型前向传播MoE https:/…

JavaIO流的使用和修饰器模式(直击心灵版)

系列文章目录 JavaIO流的使用和修饰器模式 文章目录 系列文章目录前言一、字节流&#xff1a; 1.FileInputStream(读取文件)2.FileOutputStream(写入文件) 二、字符流&#xff1a; 1..基础字符流:2.处理流&#xff1a;3.对象处理流&#xff1a;4.转换流&#xff1a; 三、修饰器…

爬虫入门re+bs4

目录 前言 1. 导入必要的库 2. 定义获取网页HTML内容的函数 get_html 3. 定义获取数据的函数 get_data 4. 定义获取文章正文内容的函数 content_text 5. 定义获取单条课程数据的函数 get_one_course_data 6. 定义保存数据的函数 save_data 7. 定义文件名合法化处理函数 sanitiz…

MySQL身份验证的auth_socket插件

在Ubuntu 20.04 LTS上&#xff0c;MySQL 8.0默认使用auth_socket插件进行身份验证&#xff0c;可能存在意想不到的情况。 一、auth_socket插件 在使用sudo mysql或通过sudo切换用户后执行任何MySQL命令时&#xff0c;不需要输入密码或错误密码都可以正常登入mysql数据库&…