一、Servlet 核心概念与生命周期
在 Java Web 开发中,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++,那么最终的计数将是不准确的。
解决方案
- 避免使用实例变量: 尽量使用局部变量,局部变量存储在栈中,是线程安全的。
- 同步机制: 使用
synchronized关键字修饰方法或代码块,但会降低性能。 - 实现 SingleThreadModel 接口: (已废弃)容器会为每个请求创建一个 Servlet 实例,不推荐。
- 使用线程安全的集合: 如
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 的作用与生命周期
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 在应用启动时初始化。
常见错误与排查思路
原因: 路径映射错误、Servlet 未注册、项目部署路径错误。
排查: 检查 web.xml 或注解中的 url-pattern,确认浏览器地址栏 URL 是否正确。
原因: 代码异常(NullPointerException, SQLException 等)。
排查: 查看服务器日志(如 Tomcat 的 logs/catalina.out),定位具体异常栈。
原因: 编码设置不一致(UTF-8 vs GBK)。
排查: 确保请求、响应、数据库、页面元标签编码统一,使用 Filter 统一设置编码。
六、总结与学习建议
掌握 servlet 常见面试题 不仅仅是背诵答案,更重要的是理解其背后的设计思想和运行机制。建议开发者:
- 动手实践: 从零搭建一个 Servlet 项目,体验生命周期。
- 阅读源码: 阅读 Tomcat 源码中关于 Servlet 容器的实现,理解 Request 和 Response 的处理流程。
- 结合框架: 将 Servlet 知识与 Spring Boot 等现代框架结合,理解自动配置的底层逻辑。
希望通过本文的深入解析,你能在面试中从容应对 servlet 常见面试题,并建立起扎实的 Java Web 基础。