JavaWeb:Servlet、Filter、Listener
一、Servlet核心:加载顺序+完整代码修正
Servlet是Java Web的核心组件,负责接收客户端HTTP请求、处理业务逻辑并返回响应结果,<load-on-startup>是控制Servlet加载时机的关键配置,也是后端面试的高频考点,精准掌握加载规则能有效优化Web应用启动性能。
Servlet是Java Web的核心组件,负责处理客户端请求并返回响应,<load-on-startup>是控制Servlet加载时机的关键配置,也是面试常考点。
1. Servlet加载顺序:load-on-startup
该标签用于配置Servlet在Web容器(如Tomcat)中的加载时机,默认情况下Servlet是首次访问时才加载,通过该标签可实现容器启动时预加载。
-
取值为负数(默认-1):Servlet在首次被客户端访问时加载、初始化
-
取值为0或正整数:Web容器启动时立即加载,数值越小,加载优先级越高;数值相同则按照web.xml中的配置顺序加载
<!-- web.xml中Servlet配置示例 -->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.demo.LoginServlet</servlet-class>
<!-- 容器启动时加载,优先级1,数值越小越早加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
2. Servlet完整代码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录Servlet,处理登录请求
* 注解@WebServlet替代web.xml的映射配置,简化开发
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
/**
* 处理GET请求:一般用于页面跳转、数据查询
* 注意:必须删除super.doGet(),父类默认返回405方法不允许错误
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应编码,解决中文乱码
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("请使用POST方式提交登录表单!");
}
/**
* 处理POST请求:一般用于表单数据提交、敏感数据传输
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 设置请求编码,适配中文参数
req.setCharacterEncoding("UTF-8");
// 2. 通过name属性获取表单参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 控制台打印参数,调试使用
System.out.println("前端传递用户名:" + username);
System.out.println("前端传递密码:" + password);
// 3. 设置响应编码,返回中文数据不乱码
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("登录请求接收成功!用户名:" + username);
}
}
易错提醒:不要保留super.doGet(req, resp)和super.doPost(req, resp),父类HttpServlet的默认实现会返回405错误,导致请求失败!
二、Filter过滤器:统一编码处理+完整实现
Filter过滤器是Java Web的核心扩展组件,主要用于拦截客户端请求和服务器响应,统一处理通用业务逻辑,比如全局编码设置、接口权限校验、请求日志记录、非法请求过滤,最大的优势是避免每个Servlet单独编写重复逻辑,大幅减少代码冗余,也是解决中文乱码最便捷的方案。
Filter过滤器用于拦截客户端请求和服务器响应,统一处理通用逻辑,比如全局编码设置、权限校验、日志记录、请求过滤,避免每个Servlet单独处理编码,减少代码冗余。
1. 编码过滤器完整代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 全局编码过滤器,统一处理请求和响应编码
* 拦截所有请求/*,覆盖所有页面和Servlet
*/
@WebFilter(filterName = "EncodingFilter", urlPatterns = "/*")
public class EncodingFilter implements Filter {
// 定义编码格式,从配置文件读取
private String encode;
/**
* 过滤器初始化:服务器启动时执行一次,读取初始化参数
*/
@Override
public void init(FilterConfig config) throws ServletException {
// 获取web.xml中配置的编码参数
this.encode = config.getInitParameter("encode");
// 兜底逻辑:无配置时默认UTF-8,避免空指针
if (encode == null || encode.isEmpty()) {
this.encode = "UTF-8";
}
System.out.println("编码过滤器初始化完成,默认编码:" + encode);
}
/**
* 核心过滤方法:每次请求都会执行
* 执行顺序:过滤前逻辑 → 放行请求 → 执行业务代码 → 过滤后逻辑
*/
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("===== 编码过滤器开始拦截请求 =====");
// 统一设置请求编码
req.setCharacterEncoding(encode);
// 统一设置响应编码和内容类型
resp.setContentType("text/html;charset=" + encode);
resp.setCharacterEncoding(encode);
// 放行请求,执行后续过滤器或Servlet业务逻辑
chain.doFilter(req, resp);
System.out.println("===== 编码过滤器请求处理完毕 =====");
}
/**
* 过滤器销毁:服务器关闭时执行一次
*/
@Override
public void destroy() {
System.out.println("编码过滤器已销毁");
}
}
2. web.xml配置过滤器初始化参数
如果不使用注解,可通过xml配置初始化编码参数,适配老项目开发:
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.demo.EncodingFilter</filter-class>
<!-- 初始化编码参数 -->
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
三、Listener监听器:Web容器生命周期监听
监听器用于监听Web容器三大域对象(ServletContext上下文、HttpSession会话、ServletRequest请求)的生命周期事件,无需手动调用,由Web容器自动触发,常用于全局数据初始化、在线用户人数统计、会话状态监控、项目启动加载配置等场景,是实现全局业务监听的核心工具。
监听器用于监听Web容器的生命周期事件(上下文、会话、请求的创建与销毁),常用于全局数据初始化、在线人数统计、会话状态监控等场景,无需手动调用,容器自动触发。
1. 通用监听器完整代码
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 全局监听器,监听三大域对象生命周期
* 实现三个核心监听接口:上下文监听、会话监听、请求监听
*/
@WebListener
public class GlobalListener implements ServletContextListener, HttpSessionListener, ServletRequestListener {
/**
* 全局上下文初始化:服务器启动时执行,只执行一次
* 常用于全局配置、数据初始化
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("【全局上下文】服务器启动,初始化完成");
// 存储全局参数,整个项目共享
sce.getServletContext().setAttribute("projectName", "JavaWeb基础Demo");
}
/**
* 全局上下文销毁:服务器关闭时执行,只执行一次
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("【全局上下文】服务器关闭,销毁完成");
}
/**
* 会话创建:用户首次访问项目时创建Session
*/
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("【会话】创建成功,SessionID:" + se.getSession().getId());
}
/**
* 会话销毁:Session超时、手动注销时执行
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("【会话】销毁成功,SessionID:" + se.getSession().getId());
}
/**
* 请求初始化:每次客户端请求都会触发
*/
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("【请求】接收到客户端请求,初始化完成");
}
/**
* 请求销毁:请求响应完毕后触发
*/
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("【请求】响应完成,请求对象销毁");
}
}
四、Java Web完整请求执行流程
理清请求完整执行顺序,才能彻底吃透Web容器底层运行机制,这也是面试中常被问到的核心问答题,清晰的执行链路能帮我们快速定位请求拦截、业务处理、响应返回过程中的问题,完整执行链路如下:
理清执行顺序,才能彻底理解Web容器运行机制,也是面试高频问答题,完整执行链路如下:
-
客户端发送HTTP请求到Web容器(Tomcat)
-
监听器触发:requestInitialized(请求初始化)
-
过滤器执行:doFilter前置逻辑(编码设置、拦截校验)
-
请求到达对应Servlet,执行doGet/doPost业务逻辑
-
过滤器执行:doFilter后置逻辑
-
监听器触发:requestDestroyed(请求销毁)
-
容器将响应结果返回给客户端
额外生命周期顺序:服务器启动 → 上下文初始化(contextInitialized) → 过滤器初始化 → 用户访问 → Session创建(sessionCreated) → 服务器关闭 → Session销毁 → 过滤器销毁 → 上下文销毁(contextDestroyed)
五、核心总结与易错点复盘
5.1 核心知识点总结
-
load-on-startup取值为负数(默认-1):Servlet首次访问时加载;取值为0或正整数:容器启动时预加载,数值越小优先级越高
-
Servlet核心避免405错误:必须删除父类doGet()、doPost()默认实现,自定义业务逻辑
-
Filter核心作用:统一拦截请求响应,chain.doFilter()是放行关键,缺少则请求无法流转
-
Listener核心作用:监听容器生命周期,自动触发,无需手动调用,实现全局业务监听
-
中文乱码终极解决方案:通过Filter全局统一设置请求、响应UTF-8编码,无需单个Servlet配置
-
请求执行固定顺序:监听器请求初始化 → 过滤器前置逻辑 → Servlet业务处理 → 过滤器后置逻辑 → 监听器请求销毁
-
id唯一供前端用,name供后端传参,表单必须加name
-
load-on-startup负数:首次访问加载;0/正数:启动加载,数值越小优先级越高
-
Filter统一处理全局逻辑,避免重复代码,chain.doFilter()必须写,否则请求无法放行
-
Listener监听容器生命周期,自动触发,无需手动调用
-
中文乱码核心解决:请求和响应统一设置UTF-8编码,过滤器全局处理最便捷
5.2 高频易错点
-
Servlet中保留super.doGet()/super.doPost(),父类默认返回405 Method Not Allowed错误
-
过滤器未配置urlPatterns拦截路径,导致过滤器完全不生效,无法拦截请求
-
过滤器忘记编写chain.doFilter(req, resp),请求被拦截无法到达Servlet,页面无响应
-
忽略全局编码配置,前端传递中文参数到后端出现乱码,响应返回中文也乱码
-
混淆Servlet加载规则,误以为load-on-startup数值越大优先级越高
-
Servlet中保留super.doGet(),导致405错误
-
表单元素忘记写name属性,后端获取参数为null
-
过滤器忘记配置urlPatterns,导致过滤器不生效
-
忽略编码设置,前端传递中文参数后端乱码
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)