1. Servlet技术概述
Servlet是JavaEE规范中用于处理Web请求的核心组件,它运行在支持Java的应用服务器中(如Tomcat、Jetty等)。作为JavaWeb开发的基石,Servlet承担着接收HTTP请求、处理业务逻辑、生成HTTP响应的关键职责。
我第一次接触Servlet是在2010年,当时还在用Tomcat 6.0。记得最清楚的是那个doGet()方法,它就像个守门人,专门处理浏览器地址栏敲回车发起的请求。十几年过去了,虽然现在各种框架层出不穷,但Servlet依然是JavaWeb开发不可绕过的基础。
重要提示:学习Servlet前需要掌握Java基础语法和HTTP协议基本知识,否则会像当年我带的实习生一样,连request和response对象都分不清楚。
2. Servlet核心工作机制
2.1 生命周期管理
Servlet的生命周期由容器全权管理,主要经历三个阶段:
- 初始化阶段:容器首次加载Servlet时调用init()方法。这里有个实际项目中的经验——不要在init()里做耗时操作。曾经有个项目在init()里初始化数据库连接池,导致应用启动要3分钟,被运维同事追着骂。
public void init(ServletConfig config) throws ServletException { // 应该只做必要的轻量级初始化 this.config = config; logger.info("Servlet初始化完成"); }服务阶段:每次请求都会调用service()方法。根据HTTP方法类型,会路由到doGet()或doPost()等具体方法。这里有个性能优化点:Servlet默认不是线程安全的,要特别注意实例变量的使用。
销毁阶段:容器关闭时调用destroy()方法释放资源。记得有次没在destroy()里关闭文件流,导致服务器上有上千个未释放的文件句柄。
2.2 请求处理流程
一个典型的Servlet处理流程如下(以Tomcat为例):
- 浏览器发起HTTP请求
- Tomcat的Connector接收请求
- Engine匹配Host和Context
- Wrapper调用对应的Servlet
- 执行service()方法
- 生成响应返回客户端
在这个过程中,有几个关键对象需要特别关注:
HttpServletRequest:封装了所有请求信息。获取参数时要注意区分getParameter()和getAttribute()的区别,这是新手常踩的坑。
HttpServletResponse:控制响应输出。设置编码一定要在getWriter()之前,否则中文乱码问题会让你怀疑人生。
ServletContext:应用全局共享对象。可以用来存储应用级别的配置,但要注意线程安全问题。
3. 实际开发中的进阶技巧
3.1 过滤器(Filter)的应用
Filter是Servlet规范中的重要补充,典型的应用场景包括:
- 权限验证:在Filter中检查session,决定是否放行请求
- 日志记录:记录请求耗时、参数等信息
- 编码处理:统一设置request/response的字符编码
public class AuthFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { HttpServletRequest req = (HttpServletRequest) request; HttpSession session = req.getSession(false); if(session == null || session.getAttribute("user") == null) { ((HttpServletResponse)response).sendRedirect("/login"); return; } chain.doFilter(request, response); } }3.2 异步Servlet处理
传统Servlet会阻塞线程直到处理完成,这在处理耗时操作时非常低效。从Servlet 3.0开始支持异步处理:
@WebServlet(urlPatterns="/async", asyncSupported=true) public class AsyncServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) { AsyncContext ctx = req.startAsync(); executorService.submit(() -> { // 模拟耗时操作 Thread.sleep(3000); ctx.getResponse().getWriter().write("Async Response"); ctx.complete(); }); } }这个特性在大文件上传、长轮询等场景特别有用。但要注意合理配置线程池,避免耗尽系统资源。
4. 常见问题排查指南
4.1 中文乱码问题
这是出现频率最高的问题之一,解决方案要分情况:
- GET请求乱码:修改Tomcat的server.xml,在Connector添加URIEncoding="UTF-8"
- POST请求乱码:在获取参数前调用request.setCharacterEncoding("UTF-8")
- 响应乱码:在获取Writer前设置response.setContentType("text/html;charset=UTF-8")
4.2 404错误排查步骤
- 检查web.xml配置或注解是否正确
- 确认context path是否匹配
- 查看Tomcat日志是否有部署错误
- 检查URL拼写(包括大小写)
4.3 内存泄漏预防
Servlet开发中常见的内存泄漏场景:
- 静态集合持续增长未清理
- 线程未正确关闭
- 第三方库资源未释放
建议使用VisualVM等工具定期检查内存使用情况。
5. 现代JavaWeb中的Servlet
虽然现在Spring Boot等框架大行其道,但Servlet仍然是底层核心。以Spring MVC为例:
- DispatcherServlet本身就是个Servlet
- 各种Filter仍然基于Servlet规范
- 底层HTTP处理还是依赖Servlet API
理解Servlet原理,能让你:
- 更高效地使用各种框架
- 更好地排查线上问题
- 更深入地理解Web工作原理
我最近做的一个电商项目中,就用原生的Servlet实现了文件断点续传功能,比某些现成组件性能提升了40%。这充分说明,扎实的Servlet基础在当今仍然非常有价值。