tomcat源码分析之filter和servlet

        学习JavaEE的时候,看的是尚学堂的视频。记得老师在介绍各种web服务器的时候,说tomcat其实应该叫做servlet容器。这一句话不说不要紧,一说就让我纠结了好几个月。当时老师讲JavaEE的时候并没有深入的讲tomcat。偶然间提到一次servlet的调用机制就觉得高贵冷艳。没有办法,当时知识有限,我只好以“tomcat本来就是servlet容器”自我安慰。
        不过这种“美好生活”没有持续多久就破灭了。原因就是了解到了struts2,这东西并没有用servlet,而是用filter实现的。我有点不相信,但是翻了很久的Struts2还是没有发现servlet的影子。可是这东西不也是在tomcat下面运行的吗?传说中的servlet容器(tomcat)莫非另有乾坤?废话到这里为止吧!大概讲了一下一个JSP菜鸟如何开始分析tomcat源码的。下面进入正题:

        我主要的参考资料是《深入剖析tomcat》的中文版,这个pdf可以在CSDN上免费下载到。这里我不想过多重复书中已经写得非常详细的内容,主要探讨一下filter和servlet的关系。当然首先还是搬运一下,下图描述了tomcat的方法调用序列。tomcat源码分析之filter和servlet_第1张图片

      具体过程如下:
                (1)connector 创建 request 和 response 对象;
                (2)connector 调用 StandardContext 实例的 invoke 方法;
                (3)StandardContext 接着调用其 pipeline 的 invoke 方法,StandardContext 中 pipeline 的 basic valve 是
  StandardContextValve,因此,StandardContext 的 pipeline 会调用 StandardContextValve 的 invoke 方法;
                (4)StandardContextValve 的 invoke 方法获取 wrapper 处理请求,调用 wrapper 的 invoke 方法;
                (5)StandardWrapper 是 Wrapper 接口的标准实现,StandardWrapper 实例的 invoke 方法会调用其
  pipeline 的 invoke 方法;
                (6)StandardWrapper 的 pipeline 中的 basic valve 是 StandardWrapperValve,因此,会调用其 invoke 方
 法,StandardWrapperValve 调用 wrapper 的 allocate 方法获取 servlet 实例;
                (7)allocate 方法调用 load 方法载入 servlet 类,若已经载入,则无需重复载入;
                (8)load 方法调用 servlet 的 init 方法;
                (9)StandardWrapperValve 调用 servlet 的 service 方法。

        这个过程倒是说得很仔细,但仍然没有看到filter的影子。不过功夫不负有心人,还是被我发现了。

			  // Create the filter chain for this request
        ApplicationFilterChain filterChain =
            createFilterChain(request, servlet);
        /*略
        String jspFile = wrapper.getJspFile();
        if (jspFile != null)
            sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
        else
            sreq.removeAttribute(Globals.JSP_FILE_ATTR);
        if ((servlet != null) && (filterChain != null)) {
            filterChain.doFilter(sreq, sres);
        }
        sreq.removeAttribute(Globals.JSP_FILE_ATTR);
        问题的答案就在上面的7,、8、9三步。在StandardWrapperValve的invoke中(也就是上面贴的代码),我们终于看到了filter的身影。倒数第三行的代码就是调用servlet的入口,传说中的doFilter()。当然对于Struts2,doFilter的作用就不是最终调用servlet的service方法了,而是形成了一种代理机制。这种机制相当于拦截的作用,Struts2中的各种filter的目的就是把Http请求路由到Action上,而不是servlet上。感觉问题还是没有解答透彻,比如对于Struts2,doFilter绑定的servlet是在哪儿初始化的?个人猜想这个servlet应该是Struts2自己弄的一个“傀儡皇帝”。后边继续研究研究。

你可能感兴趣的:(Java)