Servlet与Filter生命周期详解

在Java Web开发中,Servlet和Filter是两个核心组件,理解它们的生命周期是掌握JavaWeb开发的关键。本文将用通俗易懂的方式解析它们的生命周期全过程。

一、Servlet生命周期:三阶段模型

Servlet的生命周期由Servlet容器(如Tomcat)管理,整个过程分为三个阶段:

1. 初始化阶段(init)

  • 触发时机:当容器启动时(配置了<load-on-startup>)或第一次请求到达时
  • 核心方法init(ServletConfig config)
  • 只执行一次
  • 典型应用场景:
    public class MyServlet extends HttpServlet {
        private DatabaseConnection dbConnection;
        
        @Override
        public void init() throws ServletException {
            // 初始化数据库连接
            dbConnection = new DatabaseConnection();
            // 加载配置文件
            Properties config = loadConfig();
        }
    }
    

2. 服务阶段(service)

  • 触发时机:每次客户端请求
  • 核心方法service() -> 根据请求类型调用 doGet()/doPost()
  • 可执行多次(每次请求都会调用)
  • 线程安全问题警示:
    public class UnsafeServlet extends HttpServlet {
        private int count; // 存在线程安全问题!
        
        protected void doGet(HttpServletRequest request, HttpServletResponse response) {
            count++;
            // ...其他处理
        }
    }
    

3. 销毁阶段(destroy)

  • 触发时机:容器关闭或应用卸载时
  • 核心方法destroy()
  • 只执行一次
  • 资源清理示例:
    @Override
    public void destroy() {
        // 关闭数据库连接
        if(dbConnection != null) {
            dbConnection.close();
        }
        // 释放其他资源
        releaseResources();
    }
    

Servlet生命周期流程图

启动容器
是否配置 load-on-startup?
创建Servlet实例
等待首次请求
调用init方法
创建Servlet实例
等待请求
请求到达
调用service方法
处理请求
返回响应
容器关闭
调用destroy方法
销毁实例

二、Filter生命周期:四阶段模型

Filter的生命周期与Servlet类似但更精细:

1. 初始化阶段(init)

  • 触发时机:容器启动时
  • 核心方法init(FilterConfig filterConfig)
  • 只执行一次
  • 配置参数获取示例:
    public class LogFilter implements Filter {
        private String logPath;
        
        @Override
        public void init(FilterConfig config) {
            // 获取web.xml中配置的参数
            logPath = config.getInitParameter("logDirectory");
            // 初始化日志系统
            Logger.init(logPath);
        }
    }
    

2. 过滤请求阶段(doFilter前半段)

  • 触发时机:请求到达时
  • 核心方法doFilter()的前半部分
  • 每次匹配的请求都会执行
  • 请求预处理示例:
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        // 1. 请求到达时的预处理
        long startTime = System.currentTimeMillis();
        logRequest(request);
        
        // 2. 关键操作:将请求传递给后续过滤器或Servlet
        chain.doFilter(request, response);
        
        // 3. 响应返回时的后处理(下一阶段)
    }
    

3. 过滤响应阶段(doFilter后半段)

  • 触发时机:服务器生成响应后
  • 核心位置chain.doFilter()方法调用之后
  • 每次匹配的请求都会执行
  • 响应后处理示例:
    @Override
    public void doFilter(...) {
        // ...请求预处理
        
        chain.doFilter(request, response); // 分水岭
        
        // 响应后处理
        long duration = System.currentTimeMillis() - startTime;
        logResponse(response, duration);
        addSecurityHeaders(response);
    }
    

4. 销毁阶段(destroy)

  • 触发时机:容器关闭时
  • 核心方法destroy()
  • 只执行一次
  • 资源释放示例:
    @Override
    public void destroy() {
        // 关闭日志系统
        Logger.shutdown();
        // 释放其他资源
        cleanupResources();
    }
    

Filter生命周期流程图

容器启动
创建Filter实例
调用init方法
等待请求
请求是否匹配?
执行doFilter前半段
chain.doFilter
目标资源处理
执行doFilter后半段
返回响应
直接访问目标资源
容器关闭
调用destroy方法
销毁实例

三、Servlet vs Filter生命周期对比

特性ServletFilter
初始化init() 一次init() 一次
处理阶段service()/doXxx() 多次doFilter() 多次
销毁destroy() 一次destroy() 一次
执行顺序单实例处理请求多个Filter按配置顺序执行
核心功能处理请求并生成响应预处理请求和后处理响应
配置方式@WebServlet或web.xml@WebFilter或web.xml

四、常见问题解答

Q1:为什么Servlet和Filter都是单例?

  • 答:为了提高性能,容器为每个Servlet/Filter只创建一个实例,通过线程池处理并发请求

Q2:Filter的chain.doFilter()为什么如此重要?

  • 答:这是Filter链中的关键控制点:
    1. 调用前:对请求进行预处理
    2. 调用时:将控制权交给下一个Filter或Servlet
    3. 调用后:对响应进行后处理

Q3:如何在生命周期中安全使用实例变量?

  • 答:
    • 避免在Servlet/Filter中使用可修改的实例变量
    • 必须使用时需同步处理(但会影响性能)
    • 推荐使用局部变量或线程安全对象

Q4:如何控制初始化顺序?

  • 答:
    • Servlet:通过web.xml<load-on-startup>的值控制(值越小优先级越高)
    • Filter:通过web.xml中的配置顺序或@WebFilter的filterName排序

五、总结

通过本文的讲解,我们应该掌握:

  1. Servlet生命周期:初始化 -> 服务 -> 销毁
  2. Filter生命周期:初始化 -> 请求过滤 -> 响应过滤 -> 销毁
  3. Filter的doFilter方法是关键分界点
  4. 两者都是单例模式,需要注意线程安全问题
  5. 合理使用生命周期方法进行资源管理

生命周期是JavaWeb组件的核心概念,理解它们将帮助你编写更高效、更健壮的Web应用程序。在实际开发中,建议在init()中初始化资源,在destroy()中释放资源,避免内存泄漏问题。

示例代码可在GitHub获取https://github.com/example/servlet-filter-demo

参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值