Tomcat对Servlet规范的Filter及Listener实现(上)

简介: Tomcat对Servlet规范的Filter及Listener实现

加载Servlet的类不等于创建Servlet实例,Tomcat先加载Servlet的类,然后还得在Java堆创建Servlet实例。


一个Web应用里往往有多个Servlet,而在Tomcat中一个Web应用对应一个Context容器,即一个Context容器需管理多个Servlet实例。

但Context容器并不直接持有Servlet实例,而是通过子容器Wrapper管理Servlet,可以把Wrapper容器看作Servlet的包装。


为何需要Wrapper?Context容器直接维护一个Servlet数组还不满足?


Servlet不仅是个类实例,还有相关配置信息,比如URL映射、初始化参数,因此设计出了一个包装器,把Servlet本身和它相关的数据包起来。


管理好Servlet就够了吗?


Listener和Filter也是Servlet规范,Tomcat也要创建它们的实例,在合适时机调用它们的方法。


Servlet管理

Tomcat用Wrapper容器管理Servlet

protected volatile Servlet instance = null;

它拥有一个Servlet实例,Wrapper#loadServlet实例化Servlet:

public synchronized Servlet loadServlet() throws ServletException {
    Servlet servlet;
    // 1. 创建Servlet实例
    servlet = (Servlet) instanceManager.newInstance(servletClass);    
    // 2.调用了Servlet#init【Servlet规范要求】
    initServlet(servlet);
    return servlet;
}

为加快系统启动速度,一般采取资源延迟加载,所以Tomcat默认情况下Tomcat在启动时不会加载你的Servlet,除非把Servlet loadOnStartup参数置true。


虽然Tomcat在启动时不会创建Servlet实例,但会创建Wrapper容器。当有请求访问某Servlet,才会创建该Servlet实例。


Servlet是被谁调用呢?

Wrapper作为一个容器组件,有自己的Pipeline和BasicValve,其BasicValve为StandardWrapperValve。


当请求到来,Context容器的BasicValve会调用Wrapper容器中Pipeline中的第一个Valve,然后调用到StandardWrapperValve:

public final void invoke(Request request, Response response) {
    // 1.实例化Servlet
    servlet = wrapper.allocate();
    // 2.给当前请求创建一个Filter链
    ApplicationFilterChain filterChain =
        ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
   // 3. 调用这个Filter链,Filter链中的最后一个Filter会调用Servlet
   filterChain.doFilter(request.getRequest(), response.getResponse());
}

StandardWrapperValve的invoke就三步:

  1. 创建Servlet实例
  2. 给当前请求创建一个Filter链
  3. 调用Filter链


为何要给每个请求创建Filter链

每个请求的请求路径不同,而Filter都有相应路径映射,因此不是所有Filter都需要处理当前请求,要根据请求路径选择特定的一些Filter。



为何没调用Servlet#service

Filter链的最后一个Filter会负责调用Servlet。


Filter管理

跟Servlet一样,Filter也可在web.xml配置。

但Filter的作用域是整个Web应用,因此Filter的实例维护在Context容器:Map里存的是filterDef(filter定义),而非filter类实例


image.png


Filter链存活期很短,它跟每个请求对应。一个新请求来了,就动态创建一个Filter链,请求处理完,Filter链就被回收。

public final class ApplicationFilterChain implements FilterChain {
  // Filter链的Filter数组
  private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
  // Filter链的当前的调用位置
  private int pos = 0;
  // Filter总数
  private int n = 0;
  // 每个Filter链最终要调用的Servlet
  private Servlet servlet = null;
  public void doFilter(ServletRequest req, ServletResponse res) {
        internalDoFilter(request,response);
  }
  private void internalDoFilter(ServletRequest req,
                                ServletResponse res){
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        Filter filter = filterConfig.getFilter();
        filter.doFilter(request, response, this);
        return;
    }
    servlet.service(request, response);
}
目录
相关文章
|
8天前
|
Java 应用服务中间件 Maven
JavaWeb基础5——HTTP,Tomcat&Servlet
JavaWeb技术栈、HTTP、get和post区别、响应状态码、请求响应格数据式、IDEA使用Tomcat、报错解决、Servlet的体系结构、IDEA使用模板创建Servlet
JavaWeb基础5——HTTP,Tomcat&Servlet
|
3月前
|
NoSQL Java Redis
深入理解Servlet Filter及其限流实践
深入理解Servlet Filter及其限流实践
142 44
|
3月前
|
Java 应用服务中间件 Maven
|
3月前
|
前端开发 应用服务中间件
|
4月前
|
JSON Java 应用服务中间件
|
3月前
|
XML 数据格式
|
3月前
|
XML Java 应用服务中间件
|
3月前
|
前端开发 Java 应用服务中间件
|
4月前
|
Java
springboot项目出现Exception in thread “main“ java.lang.NoClassDefFoundError: javax/servlet/Filter
springboot项目出现Exception in thread “main“ java.lang.NoClassDefFoundError: javax/servlet/Filter
150 0
|
4月前
|
XML 前端开发 Java
Tomcat和Servlet
Tomcat和Servlet
33 0