杰瑞科技汇

Servlet如何处理请求与响应?

Servlet 是什么?(核心概念)

Servlet(Server Applet)是运行在 Web 服务器或应用服务器上的、用 Java 编写的程序,它的主要作用是接收并响应来自客户端(通常是浏览器)的 HTTP 请求

Servlet如何处理请求与响应?-图1
(图片来源网络,侵删)

你可以把它想象成一个“Web 请求处理器”“中间人”,当你在浏览器中输入一个网址并回车后,这个请求会发送到服务器,服务器上的 Servlet 就会“醒来”,处理这个请求,然后生成一个 HTML 页面或其他格式的响应,再发送回你的浏览器。

Servlet 的核心作用:

  1. 接收请求:解析客户端发送过来的 HTTP 请求,包括请求头、请求参数、Cookie 等。
  2. 处理业务逻辑:执行 Java 代码,比如查询数据库、进行计算、调用其他服务等。
  3. 生成响应:根据业务逻辑的处理结果,构建一个 HTTP 响应,通常是 HTML 页面,也可以是 JSON、XML 等数据。
  4. 发送响应:将构建好的 HTTP 响应发送回客户端浏览器。

Servlet 的工作原理(宏观流程)

Servlet 的工作离不开一个关键的容器——Servlet 容器,也就是我们常说的 Web 容器应用服务器,Tomcat、Jetty、WildFly 等,Servlet 本身只是一个接口,不能独立运行,必须依赖于 Servlet 容器。

下面是 Servlet 处理一个 HTTP 请求的完整流程:

Servlet如何处理请求与响应?-图2
(图片来源网络,侵删)
  1. 客户端发送请求:用户在浏览器中输入 http://localhost:8080/myApp/login 并回车。
  2. 服务器接收请求:Web 服务器(如 Tomcat)监听在 8080 端口,接收到这个 HTTP 请求。
  3. 解析请求并定位 Servlet:Tomcat 会解析请求的 URL,根据 web.xml 配置文件(或注解)找到处理这个 URL 的 Servlet(LoginServlet)。
  4. 创建 Request 和 Response 对象:Tomcat 会创建两个核心对象:
    • HttpServletRequest:封装了所有的 HTTP 请求信息(请求行、请求头、请求参数等)。
    • HttpServletResponse:这是一个“空白”的响应对象,用来后续构建和发送响应。
  5. 调用 Servlet 服务方法:Tomcat 调用 LoginServlet 实例的 service() 方法,并将创建好的 requestresponse 对象作为参数传入。
  6. Servlet 处理请求
    • service() 方法会根据请求的类型(GET, POST 等)调用相应的 doGet()doPost() 方法。
    • doGet()doPost() 方法中,开发者可以:
      • 通过 request.getParameter() 获取表单数据。
      • 调用业务逻辑层代码(如 Service、DAO)处理数据。
      • 通过 response.setContentType() 设置响应内容类型(如 text/html)。
      • 通过 response.getWriter() 获取输出流,向响应体中写入 HTML 内容。
  7. 生成并返回响应:Servlet 处理完毕后,Tomcat 会将 response 对象中的内容(状态码、响应头、响应体)组装成一个完整的 HTTP 响应。
  8. 发送响应给客户端:Tomcat 将这个 HTTP 响应发送回浏览器。
  9. 浏览器渲染页面:浏览器接收到响应后,解析 HTML 并将其渲染成用户看到的页面。

Servlet 的生命周期

Servlet 的生命周期由 Servlet 容器管理,主要包括三个阶段:初始化、服务、销毁

初始化阶段 (init())

  • 何时触发:当 Servlet 第一次被请求时,或者当服务器启动时(如果配置了 load-on-startup)。
  • 特点
    • 这个方法只被调用一次
    • 它在 service() 方法之前执行。
    • 主要用于执行一次性的初始化操作,比如加载数据库驱动、创建连接池、读取配置文件等。
  • 代码示例
    @Override
    public void init() throws ServletException {
        // 只在第一次创建 Servlet 实例时调用一次
        System.out.println("Servlet 正在初始化...");
        // 在这里执行初始化代码
    }

服务阶段 (service(), doGet(), doPost())

  • 何时触发:每当有请求指向该 Servlet 时,容器就会调用此方法。

  • 特点

    • 对于每一个请求,容器都会在同一个 Servlet 实例上调用 service() 方法。
    • service() 方法是入口,它会根据请求的 HTTP 方法(GET, POST, PUT, DELETE 等)来调用对应的 doGet(), doPost() 等方法。
    • 因为同一个实例会处理多个请求,所以开发者必须确保 service() 方法的线程安全,不要在方法内部修改实例变量,除非使用同步机制。
  • 代码示例

    Servlet如何处理请求与响应?-图3
    (图片来源网络,侵删)
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理 GET 请求
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h1>你好,Servlet!</h1>");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理 POST 请求
        String username = req.getParameter("username");
        // ... 业务逻辑 ...
    }

销毁阶段 (destroy())

  • 何时触发:当 Servlet 容器决定要移除这个 Servlet 实例时(服务器关闭或应用被卸载)。
  • 特点
    • 这个方法也只被调用一次
    • 它在 Servlet 实例被垃圾回收之前执行。
    • 主要用于执行资源释放操作,比如关闭数据库连接、释放文件句柄等。
  • 代码示例
    @Override
    public void destroy() {
        // 在 Servlet 被销毁时调用一次
        System.out.println("Servlet 正在销毁...");
        // 在这里执行资源释放代码
    }

Servlet 的 API 核心组件

  1. javax.servlet.Servlet 接口

    • 所有 Servlet 必须实现的顶级接口,定义了 init(), service(), destroy() 三个生命周期方法。
  2. javax.servlet.http.HttpServlet 抽象类

    • 这是开发 Web 应用最常用的类,它继承自 GenericServlet,并提供了针对 HTTP 协议的 service() 方法的实现,这个 service() 方法会根据请求的 Method(GET, POST 等)来调用对应的 doGet(), doPost() 等方法,我们通常只需继承 HttpServlet 并重写 doGet()doPost() 即可。
  3. HttpServletRequest 接口

    • 代表客户端的请求,包含了所有请求信息,常用方法:
      • String getParameter(String name):获取请求参数。
      • String getRequestURI():获取请求的 URI。
      • getSession():获取或创建 HttpSession 对象(用于会话管理)。
  4. HttpServletResponse 接口

    • 代表服务器的响应,用来构建和发送响应给客户端,常用方法:
      • PrintWriter getWriter():获取字符输出流,用于输出文本内容(如 HTML)。
      • ServletOutputStream getOutputStream():获取字节输出流,用于输出二进制内容(如图片、文件)。
      • void setContentType(String type):设置响应内容的 MIME 类型(如 text/html, application/json)。
      • void sendRedirect(String location):发送重定向响应。

Servlet 的优缺点

优点

  • 平台无关性:基于 Java 的“一次编写,到处运行”特性。
  • 高性能:Servlet 在容器中以多线程方式运行,比传统的 CGI(通用网关接口)程序性能高得多,每个请求一个线程,而不是一个进程。
  • 健壮性:Servlet 由 Java 语言编写,拥有 Java 的所有优势,如自动垃圾回收、异常处理机制、内存管理等。
  • 可扩展性和可维护性:基于面向对象的设计,易于扩展和维护,可以与其他 Java EE(现为 Jakarta EE)技术(如 JSP, EJB, JNDI)无缝集成。
  • 安全性:Servlet 运行在 JVM 中,受到 Java 安全管理器的保护,可以有效防止许多常见的安全攻击。

缺点

  • 开发繁琐:原生 Servlet API 比较底层,需要处理很多细节,如手动获取参数、手动拼接 HTML、手动处理会话等,开发效率较低。
  • 视图与逻辑耦合:在早期的 Servlet 开发中,通常需要在 Java 代码中用 out.println() 输出 HTML,导致业务逻辑和页面视图高度耦合,难以维护。
  • 配置复杂:在 Servlet 3.0 之前,所有配置都需要在 web.xml 文件中进行,对于大型项目来说,配置文件会变得非常臃肿。

Servlet 的演进与现代地位

正是因为原生 Servlet 开发的繁琐,催生了各种 Web 框架的出现。

  • JSP (JavaServer Pages):为了解决视图与逻辑耦合的问题,JSP 应运而生,它允许在 HTML 中嵌入 Java 代码,实现了“视图”和“控制”的初步分离,但很快,人们发现 JSP 过于灵活,导致逻辑和视图又混合在了一起。
  • MVC 框架:为了彻底解决架构问题,基于 Servlet 的 MVC(Model-View-Controller)框架如 StrutsSpring MVC 等成为主流,它们封装了 Servlet 的底层细节,提供了清晰的分层结构(模型、视图、控制器),大大提高了开发效率和代码的可维护性。
    • Spring MVC 的核心就是一个 DispatcherServlet(前端控制器),它接收所有请求,然后根据配置将请求分发给具体的 Controller(处理器方法)。

现代 Servlet 的地位:

虽然我们日常开发中大多使用 Spring MVC、Jakarta EE 等“高级”框架,但这些框架的底层基石依然是 Servlet

  • 框架的本质:Spring MVC、Struts 等框架,本质上是对 Servlet 的一次高级封装,它们简化了开发,但最终生成响应的流程,依然是通过 HttpServletResponse 对象来完成的。
  • 理解 Servlet 的重要性:理解 Servlet 原理是理解所有 Java Web 框架的基础,它能让你明白 Web 请求的底层处理机制,帮助你更好地调试问题、优化性能,并在框架层面进行更深入的定制和开发。
特性 描述
核心定义 运行在服务器端的 Java 小程序,用于处理 HTTP 请求和响应。
运行环境 必须运行在 Servlet 容器(如 Tomcat)中。
工作流程 客户端请求 -> 服务器接收 -> 容器创建 Request/Response -> 调用 Servlet -> 处理并返回响应 -> 客户端接收。
生命周期 init() (一次) -> service() (每次请求) -> destroy() (一次)。
线程安全 单实例多线程,开发者需注意线程安全问题。
现代角色 是所有 Java Web 框架(如 Spring MVC)的底层基石,理解其原理至关重要。
分享:
扫描分享到社交APP
上一篇
下一篇