什么是 Servlet?常见Servlet容器

发布于:2025-09-06 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. Servlet 概述

    Servlet 是 Java EE 规范的一部分,它是一种用于 处理客户端请求并生成动态 Web 内容 的 Java 服务器端组件。Servlet 运行在 Servlet 容器(如 Tomcat、Jetty、JBoss) 中,通常用于开发 Web 应用程序。


2. Servlet 的特点

  • 基于 Java,平台无关,可移植性强。
  • 生命周期由 Servlet 容器管理,包括加载、初始化、处理请求和销毁。
  • 高效,一个 Servlet 线程可处理多个请求,而不是为每个请求创建新实例(采用线程池)。
  • 支持会话管理(如 HttpSession)。
  • 可与 JSP 结合使用,实现 MVC 模式中的控制层。

3. Servlet 的生命周期

Servlet 的生命周期由 Servlet 容器(如 Tomcat) 进行管理,主要包括以下阶段:

  1. 加载(Load)

    • 当 Web 服务器启动或收到第一个请求时,Servlet 容器会加载 Servlet 类。
  2. 初始化(init 方法)

    • 由容器调用 init(ServletConfig config) 进行初始化,只执行一次。
  3. 处理请求(service 方法)

    • 每次客户端请求时,容器调用 service(HttpServletRequest req, HttpServletResponse resp),然后再调用对应的 doGet()doPost() 处理请求。
  4. 销毁(destroy 方法)

    • 当 Servlet 容器关闭或应用程序卸载时,destroy() 方法被调用,可用于释放资源。

Servlet 生命周期示意图:

加载 -> init() -> service() -> destroy()


4. 编写一个简单的 Servlet

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html");
        response.getWriter().println("<h1>Hello, Servlet!</h1>");
    }
}

 说明:

  • @WebServlet("/hello"):定义 Servlet 访问路径 http://localhost:8080/hello
  • doGet() 处理 GET 请求,并返回 Hello, Servlet! 的 HTML 响应

5. Servlet vs JSP

对比项 Servlet JSP
本质 Java 类 HTML + Java 代码
侧重点 主要用于业务逻辑 主要用于页面展示
可读性 代码较复杂,不易维护 可读性更好,类似 HTML
执行速度 直接编译成 .class,执行速度快 需先转换成 Servlet 再编译,性能稍低
适用场景 处理请求、调用业务逻辑、返回响应 显示动态页面,如 HTML 及用户界面

6. Servlet 容器(Web 服务器)

Servlet 需要运行在 支持 Servlet 规范的容器 中,如:

  • Apache Tomcat
  • Jetty
  • JBoss
  • GlassFish

这些容器管理 Servlet 的生命周期,并提供 HTTP 请求的支持。


7. Servlet 的应用场景

  • 处理用户请求(如登录、注册)
  • 生成动态网页内容
  • 处理表单提交
  • 开发 REST API(使用 HttpServlet
  • 作为控制器(Controller),用于 MVC 设计模式

8.面试高频问答:

1. Servlet 和 JSP 的区别?

对比项 Servlet JSP
本质 Java 类 HTML + Java 代码
侧重点 主要用于业务逻辑 主要用于页面展示
可读性 代码较复杂,不易维护 可读性更好,类似 HTML
执行速度 直接编译成 .class,执行速度快 需先转换成 Servlet 再编译,性能稍低
适用场景 处理请求、调用业务逻辑、返回响应 显示动态页面,如 HTML 及用户界面

回答要点:

  • Servlet 主要处理请求、编写业务逻辑,JSP 主要用于前端页面展示。
  • JSP 最终会被转换成 Servlet,执行效率略低于直接使用 Servlet。
  • 现代开发通常采用 Servlet + JSPSpring MVC + Thymeleaf 进行开发。

2. Servlet 的生命周期是怎样的?

Servlet 生命周期包括 4 个阶段:

  1. 加载(Load): Web 服务器启动时,Servlet 类被加载。
  2. 初始化(init): 调用 init() 方法,仅执行一次。
  3. 请求处理(service): 服务器调用 service() 方法,根据请求类型执行 doGet()doPost()
  4. 销毁(destroy): 服务器关闭时,调用 destroy() 释放资源。

代码示例

@Override
public void init() throws ServletException {
    System.out.println("Servlet 初始化...");
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
    resp.getWriter().println("处理请求...");
}

@Override
public void destroy() {
    System.out.println("Servlet 被销毁...");
}

 回答要点:

  • init() 在 Servlet 加载时执行一次。
  • service() 处理 HTTP 请求,每次请求都会执行。
  • destroy() 在服务器关闭或卸载应用时执行,负责资源清理。

3. Servlet 线程是如何工作的?

Servlet 采用 多线程模型,即 一个 Servlet 实例处理多个请求,避免创建多个实例造成的资源浪费。

  • 每个请求都会创建一个新的线程(Worker 线程)。
  • 多个线程共享同一个 Servlet 实例,避免高并发下创建大量对象的开销。
  • Servlet 不是线程安全的,如果 Servlet 需要共享资源(如全局变量),需使用 synchronizedThreadLocal 进行线程同步。

代码示例:

public class ThreadUnsafeServlet extends HttpServlet {
    private int count = 0; // 共享变量,可能引发线程安全问题

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        count++; // 非线程安全
        resp.getWriter().println("访问次数:" + count);
    }
}

解决方案:

  • 使用 局部变量(线程安全)。
  • 使用 synchronized 关键字 保护共享资源。
  • 使用 ThreadLocal 变量,确保每个线程有独立的副本。

4. Servlet 如何获取请求参数?

Servlet 通过 HttpServletRequest 对象获取请求参数:

获取 GET 请求参数:

String name = request.getParameter("name");
System.out.println("获取到的 name 参数:" + name);

示例 URL: http://localhost:8080/hello?name=Tom

获取 POST 请求参数:

BufferedReader reader = request.getReader();
String body = reader.lines().collect(Collectors.joining());
System.out.println("请求体:" + body);

获取所有参数:

Map<String, String[]> params = request.getParameterMap();
params.forEach((key, values) -> System.out.println(key + ": " + Arrays.toString(values)));

回答要点:

  • request.getParameter("name") 获取单个参数值。
  • request.getParameterMap() 获取所有请求参数。
  • GET 请求参数来自 URL,POST 请求参数通常在请求体中。

5. 如何在 Servlet 中实现会话管理(Session 机制)?

Servlet 主要通过 Session(HttpSessionCookie 实现会话管理。

方法 1:使用 HttpSession
HttpSession session = request.getSession();
session.setAttribute("user", "Tom"); // 存储数据
String user = (String) session.getAttribute("user"); // 获取数据
session.invalidate(); // 销毁 session

特点:

  • Session 依赖 JSESSIONID(存储在 Cookie 中)。
  • 生命周期默认 30 分钟(可配置)。
  • 适用于存储用户信息,如登录状态。
方法 2:使用 Cookie
Cookie cookie = new Cookie("user", "Tom");
cookie.setMaxAge(3600); // 设置 Cookie 过期时间(秒)
response.addCookie(cookie);

获取 Cookie:

Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
    if ("user".equals(cookie.getName())) {
        System.out.println("Cookie 值:" + cookie.getValue());
    }
}

回答要点:

  • HttpSession 适用于存储短期用户信息,生命周期受服务器控制。
  • Cookie 适用于存储长期信息(如用户偏好设置),生命周期受浏览器控制。
  • Session 更安全,Cookie 可能被客户端篡改(可使用 HttpOnly 限制)。

6. forwardredirect 的区别?

对比项 forward redirect
本质 服务器内部跳转 客户端跳转
地址栏 地址栏不变 地址栏变化
是否需要重新请求 ❌ 不需要 ✅ 需要
数据共享 ✅ 可共享 request 作用域数据 ❌ 不能共享
适用场景 内部资源跳转 跳转到外部网站或新的路径

示例:

  • 服务器内部跳转(forward):
request.getRequestDispatcher("/dashboard.jsp").forward(request, response);
  • 客户端跳转(redirect):
response.sendRedirect("https://www.google.com");

回答要点:

  • forward 适用于 同一 Web 应用内部跳转,不刷新地址栏。
  • redirect 适用于 不同 Web 应用之间的跳转,地址栏会更新。

总结

        Servlet 是 Java EE 中用于 处理 Web 请求的核心组件,负责接收 HTTP 请求、处理业务逻辑并返回响应。在现代 Java Web 开发中,Servlet 通常与 JSP、Spring MVC、Spring Boot 结合使用,提升开发效率。

如果觉得这篇博客对你有帮助,记得点赞 ⭐、收藏 📌、关注 🚀!


网站公告

今日签到

点亮在社区的每一天
去签到