一、Servlet 核心概念与生命周期

在 Java Web 开发中,servlet 常见面试题 永远绕不开的核心就是其生命周期。面试官通常会询问 Servlet 是如何被创建、如何响应请求以及如何被销毁的。理解这一点是掌握整个 Servlet 规范的基础。

Servlet 生命周期三阶段
  • 初始化阶段 (Initialization): 当 Servlet 容器首次加载 Servlet 时,会调用 init() 方法。该方法在整个 Servlet 生命周期中只执行一次。如果配置了 <load-on-startup>,则在容器启动时立即初始化,否则在第一次请求时初始化。
  • 服务阶段 (Service): 这是 Servlet 最核心的阶段。每当有一个请求到达时,容器就会调用 service() 方法。service() 方法会根据 HTTP 请求类型(GET, POST, PUT, DELETE 等)分发给对应的 doGet(), doPost() 等方法处理。
  • 销毁阶段 (Destruction): 当 Servlet 容器关闭或 Web 应用被移除时,容器会调用 destroy() 方法。该方法也只执行一次,用于释放资源(如关闭数据库连接、保存状态等)。
public class MyServlet extends HttpServlet {
    // 1. 初始化,只调用一次
    @Override
    public void init() throws ServletException {
        System.out.println("Servlet 初始化...");
    }
    // 2. 处理请求,每次请求调用
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        // 业务逻辑处理
        resp.getWriter().write("Hello Servlet");
    }
    // 3. 销毁,只调用一次
    @Override
    public void destroy() {
        System.out.println("Servlet 销毁...");
    }
}

二、Servlet 线程安全问题深度解析

在 servlet 常见面试题 中,线程安全是一个高频考点。很多初学者认为 Servlet 是多实例的,但实际上,默认情况下,Servlet 容器(如 Tomcat)使用单例模式来管理 Servlet 实例。

为什么会有线程安全问题?

因为只有一个实例,所以当多个线程同时访问该 Servlet 时,它们会共享实例变量(成员变量)。如果这些变量被修改,就会引发数据不一致。

示例: 如果在一个 Servlet 中定义了 private int count = 0;,并在 doGet 中执行 count++,那么最终的计数将是不准确的。

解决方案

  1. 避免使用实例变量: 尽量使用局部变量,局部变量存储在栈中,是线程安全的。
  2. 同步机制: 使用 synchronized 关键字修饰方法或代码块,但会降低性能。
  3. 实现 SingleThreadModel 接口: (已废弃)容器会为每个请求创建一个 Servlet 实例,不推荐。
  4. 使用线程安全的集合: 如 ConcurrentHashMap。

三、ServletConfig 与 ServletContext

理解这两个接口的区别是掌握 Servlet 配置管理的关键。它们在 servlet 常见面试题 中经常成对出现。

特性 ServletConfig ServletContext
范围 单个 Servlet 整个 Web 应用
获取方式 getServletConfig() getServletContext() 或 getServletConfig().getServletContext()
配置来源 <servlet> 下的 <init-param> <web-app> 下的 <context-param>
作用 获取当前 Servlet 的初始化参数 获取全局参数、共享数据、资源文件

四、过滤器 Filter 与 监听器 Listener

除了核心 Servlet,servlet 常见面试题 还经常考察 AOP 思想在 Web 层的应用,即 Filter 和 Listener。

过滤器 (Filter)
监听器 (Listener)
Cookie & Session

Filter 的作用与生命周期

Filter 主要用于拦截请求和响应,常用于编码设置、权限校验、日志记录等。

  • init(): 容器启动时调用,初始化 Filter。
  • doFilter(): 每次请求经过 Filter 时调用。可以通过 chain.doFilter() 将请求传递给下一个 Filter 或 Servlet。
  • destroy(): 容器关闭时调用。
public class EncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        chain.doFilter(req, resp); // 继续执行
    }
}

Listener 的类型

Listener 用于监听 Web 应用的各个域对象(ServletContext, HttpSession, HttpServletRequest)的生命周期和属性变化。

  • ServletContextListener: 监听 ServletContext 的创建和销毁,常用于初始化全局资源(如数据库连接池)。
  • HttpSessionListener: 监听 Session 的创建和销毁,可用于统计在线人数。
  • ServletRequestListener: 监听请求的创建和销毁。

五、网友们还关心:Servlet 周边知识拓展

在深入理解 servlet 常见面试题 的基础上,了解以下周边知识能显著提升你的技术深度,帮助你在面试中脱颖而出。

Servlet 3.0 新特性

支持注解配置(@WebServlet, @WebFilter),异步处理(AsyncContext),以及可插拔性(Plugin)。这些特性简化了开发流程。

Servlet 与 Spring MVC

Spring MVC 本质上是一个 Servlet。DispatcherServlet 是一个前端控制器 Servlet,它负责分发请求到具体的 Handler。理解 Servlet 有助于理解 Spring MVC 的工作原理。

连接池技术

在 Servlet 中,通常不直接创建数据库连接,而是使用连接池(如 HikariCP, Druid)。这可以通过 ServletContextListener 在应用启动时初始化。

常见错误与排查思路

错误 404

原因: 路径映射错误、Servlet 未注册、项目部署路径错误。

排查: 检查 web.xml 或注解中的 url-pattern,确认浏览器地址栏 URL 是否正确。

错误 500

原因: 代码异常(NullPointerException, SQLException 等)。

排查: 查看服务器日志(如 Tomcat 的 logs/catalina.out),定位具体异常栈。

乱码问题

原因: 编码设置不一致(UTF-8 vs GBK)。

排查: 确保请求、响应、数据库、页面元标签编码统一,使用 Filter 统一设置编码。

六、总结与学习建议

掌握 servlet 常见面试题 不仅仅是背诵答案,更重要的是理解其背后的设计思想和运行机制。建议开发者:

  1. 动手实践: 从零搭建一个 Servlet 项目,体验生命周期。
  2. 阅读源码: 阅读 Tomcat 源码中关于 Servlet 容器的实现,理解 Request 和 Response 的处理流程。
  3. 结合框架: 将 Servlet 知识与 Spring Boot 等现代框架结合,理解自动配置的底层逻辑。

希望通过本文的深入解析,你能在面试中从容应对 servlet 常见面试题,并建立起扎实的 Java Web 基础。