Servlet 的生命周期详解

目录

1、Servlet 的生命周期

2、Spring 中一个 Controller 是一个Servlet 吗?

3、在 Spring 中有多少个 Servlet ?

4、DispatcherServlet 的生命周期

5、Servlet 生命周期和 ServletRequest 生命周期的区别


1、Servlet 的生命周期

        Servlet 生命周期指的是 Servlet 对象从创建到销毁的整个过程,包括以下阶段:

  1. 加载和实例化阶段(loading and instantiation):当 Servlet 容器启动或者第一次请求某个 Servlet 时,会加载并创建 Servlet 对象的实例。在此阶段,容器会调用 ServletContext 的 getServlet 方法来获取 Servlet 实例,并调用其 init 方法进行初始化。在 init 方法中,Servlet 可以进行一些初始化工作,如加载配置文件、建立数据库连接等。

  2. 就绪阶段(ready):当 Servlet 初始化完成后,容器会将其放入就绪状态,表示它已经准备好处理客户端请求了。

  3. 请求处理阶段(request handling):当客户端发起请求时,Servlet 容器会为每个请求创建一个新的线程,并调用 Servlet 的 service 方法处理请求。在 service 方法中,Servlet 可以读取请求数据、进行业务处理,并生成响应数据发送给客户端。

  4. 销毁阶段(destruction):当 Servlet 容器关闭或者 Web 应用程序被卸载时,会调用 Servlet 的 destroy 方法,此时 Servlet 会执行一些清理工作,如关闭数据库连接、保存会话数据等。在销毁阶段结束后,Servlet 实例将被销毁并释放资源。

        需要注意的是,Servlet 生命周期中 init 和 destroy 方法只会在 Servlet 实例创建和销毁时被调用一次,而 service 方法则会在每个请求到达时被调用一次。此外,Servlet 还可以实现其他生命周期方法,如 init(ServletConfig config)、getServletConfig() 等,以提供更加灵活的初始化和配置方式。

        一般情况下,Servlet只有在容器关闭时才会被销毁,但也可以通过Servlet的destroy()方法手动销毁Servlet。当Servlet不再被需要时,可以通过调用destroy()方法来释放资源、关闭数据库连接、取消注册等操作。Servlet的生命周期是整个应用程序中Servlet的初始化、请求处理和销毁的过程

        Servlet 生命周期流程如下图所示:

        下面通过一个案例加深对 Servlet 生命周期的理解:

@WebServlet("/myServletLife")
public class MyServletLife extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private int initCount = 0;
    private int httpCount = 0;
    private int destoryCount = 0;

    @Override
    public void destroy() {
        destoryCount++;
        super.destroy();
        // 向控制台输出destory方法被调用次数
        System.out.println(
                "**********************************destroy方法:" + destoryCount + "*******************************");
    }

    @Override
    public void init() throws ServletException {
        initCount++;
        super.init();
        // 向控制台输出init方法被调用次数
        System.out.println("调用init方法:" + initCount);
    }

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        httpCount++;
        // 控制台输出doGet方法次数
        System.out.println("doGet方法:" + httpCount);
        // 设置返回页面格式与字符集
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        // 向页面输出
        writer.write("初始化次数:" + initCount + "<br/>" + "处理请求次数:" + httpCount + "<br/>" + "销毁次数:" + destoryCount);
        writer.close();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }
}

        启动 Tomcat,在地址栏输入“localhost:8080/web/myServletLife”,多次访问 MyServlet,结果如下图。

        关闭 Tomcat 服务器,控制台输出如下图 

2、Spring 中一个 Controller 是一个Servlet 吗?

        在 Spring 中,每个 Controller 类并不是一个 Servlet,而是通过 Servlet 映射器(HandlerMapping)和适配器(HandlerAdapter)来将 HTTP 请求映射到相应的方法进行处理

        具体来说,Spring MVC 框架使用了 DispatcherServlet 作为前置控制器,负责接收客户端的请求并将请求分发给相应的 Controller 进行处理。DispatcherServlet 会根据配置的 Servlet 映射器和适配器来选择合适的 Controller 类,并将请求转发给该类中的具体方法进行处理。在方法中,可以通过注解来定义请求参数、返回值和异常处理等信息,从而更加方便地实现业务逻辑的编写。

        因此,虽然每个 Controller 类并不是一个 Servlet,但在 Spring MVC 框架中,它们可以像 Servlet 一样接收并处理 HTTP 请求。同时,Spring 还提供了很多方便的注解和工具类来简化 Controller 类的编写,使得开发者可以更加专注于业务逻辑的实现。

// Controller 只是 springmvc 中的处理器,通过 Servlet 映射器去匹配

3、在 Spring 中有多少个 Servlet ?

        在一个 Spring 应用程序中,通常会有一个或多个 Servlet。其中,最常见的是 DispatcherServlet,它是 Spring MVC 框架的核心组件之一,负责接收客户端请求并将请求分发给相应的 Controller 进行处理。

        除了 DispatcherServlet,Spring 还提供了一些其他的 Servlet,包括:

  1. ContextLoaderServlet:用于在 Web 应用程序启动时加载 Spring 配置文件,并将 ApplicationContext 对象存储在 ServletContext 中供其他组件使用。

  2. FrameworkServlet:是 DispatcherServlet 的父类,用于处理与 Spring 框架相关的 Servlet 请求,如请求映射、视图解析等。

  3. HttpPutFormContentFilter:用于处理 PUT 请求中的表单数据。

  4. OpenEntityManagerInViewFilter:用于在 Web 请求结束时自动关闭 EntityManager,以避免因为长时间持有 EntityManager 导致的内存泄漏。

  5. DelegatingFilterProxy:是一个通用的过滤器代理,可以将过滤器的实现委托给 Spring 容器中的任意一个 Bean 实例。

        需要注意的是,除了 DispatcherServlet 外,其他的 Servlet 大多是一些辅助性的组件,用于解决一些特定的问题,如处理 PUT 请求中的表单数据、自动关闭 EntityManager 等。开发者在使用 Spring 框架时,一般只需要关注 DispatcherServlet 的配置和使用即可。

4、DispatcherServlet 的生命周期

        DispatcherServlet 是 Spring MVC 框架中的一个核心组件,它作为前置控制器负责接收客户端请求并将请求分发给相应的 Controller 进行处理。它的生命周期可以分为以下几个阶段:

  1. 初始化阶段(Initialization):在容器启动时,Servlet 容器会自动创建 DispatcherServlet 实例并调用其 init() 方法进行初始化。在初始化阶段中,DispatcherServlet 会读取并解析配置文件(如 web.xml 或注解配置等),创建必要的组件对象(如 HandlerMapping、HandlerAdapter 等),并将它们存储在 ServletContext 中,以便于在后续的请求处理中使用。

  2. 请求处理阶段(Request Handling):当客户端发送请求时,Servlet 容器会将请求交给 DispatcherServlet 进行处理。在请求处理阶段中,DispatcherServlet 会根据配置的 HandlerMapping 找到匹配的 Controller,然后调用相应的 Controller 方法进行处理。在方法执行过程中,DispatcherServlet 会根据配置的 HandlerAdapter 对请求参数进行解析,将其转换为方法所需的类型,并将方法的执行结果封装为 ModelAndView 对象。最后,DispatcherServlet 会调用 ViewResolver 将 ModelAndView 对象转换为相应的视图,并将视图渲染后的结果返回给客户端。

  3. 销毁阶段(Destruction):当 Servlet 容器关闭时,会调用 DispatcherServlet 的 destroy() 方法进行销毁。在销毁阶段中,DispatcherServlet 会释放所有的资源(如 HandlerMapping、HandlerAdapter 等),并清除 ServletContext 中的相应对象。

        需要注意的是,由于 DispatcherServlet 是一个单例对象,因此它的生命周期与整个应用程序的生命周期是一致的,即在应用程序启动时创建,在应用程序关闭时销毁。在处理请求时,DispatcherServlet 会创建一个新的线程来处理每个请求,因此它的请求处理阶段是并发的,可以处理多个请求同时到达的情况。

        DispatcherServlet 异步处理请求的源码展示:

        在 DispatcherServlet 中创建新的线程来处理请求的代码位于 doService() 方法中。以下是部分源码示例:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取处理器
    HandlerExecutionChain mappedHandler = getHandler(request);
    // 获取处理器适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // 使用 Callable 封装请求和响应
    final ModelAndView exMv = ha.handle(request, response, mappedHandler.getHandler());
    // 创建新线程处理请求
    if (asyncManager.isConcurrentHandlingStarted()) {
        return;
    }
    // 判断是否支持异步处理
    if (exMv != null && exMv.isAsyncStarted()) {
        if (isAsyncDispatch(request)) {
            // 使用 Spring 的异步机制进行处理
            if (request.getAsyncContext().getTimeout() > 0) {
                asyncManager.setTaskTimeout(request.getAsyncContext().getTimeout());
            }
            asyncManager.startCallableProcessing(new DispatcherServletCallable(exMv), request, response, mappedHandler.getHandler());
            return;
        }
    }
    // 同步处理请求
    ha.handle(request, response, mappedHandler.getHandler());
}

        可以看到,在 doService() 方法中,当判断可以使用异步处理时,DispatcherServlet 会使用 Spring 的异步机制进行处理,其中 asyncManager.startCallableProcessing() 方法会创建一个新的线程来处理请求。这样就实现了异步处理请求,提高了系统的吞吐量和响应速度。

5、Servlet 生命周期和 ServletRequest 生命周期的区别

        Servlet的生命周期是整个应用程序中Servlet的初始化、请求处理和销毁的过程,而ServletRequest的生命周期是单次请求中HttpServletRequest和HttpServletResponse对象的创建和销毁的过程。

        具体来说,当Servlet容器接收到一个请求时,容器会为该请求创建一个新的HttpServletRequest对象和HttpServletResponse对象,这两个对象只在当前请求中有效,处理完请求后会被销毁,如果是同一个客户端发起的新请求,Servlet容器会再次创建HttpServletRequest和HttpServletResponse对象。// req和rep只在当前请求中有效,处理完请求后会被销毁,可以理解为方法的出栈

        在ServletRequest的生命周期中,HttpServletRequest和HttpServletResponse对象会被传递给Servlet的service()方法,Servlet可以通过这两个对象获取请求参数、设置响应头、发送响应数据等操作。当请求处理完毕后,Servlet容器会自动销毁HttpServletRequest和HttpServletResponse对象,释放资源。

        所以,Servlet的生命周期是应用程序级别的,而ServletRequest的生命周期是请求级别的。

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值