不过这种“美好生活”没有持续多久就破灭了。原因就是了解到了struts2,这东西并没有用servlet,而是用filter实现的。我有点不相信,但是翻了很久的Struts2还是没有发现servlet的影子。可是这东西不也是在tomcat下面运行的吗?传说中的servlet容器(tomcat)莫非另有乾坤?废话到这里为止吧!大概讲了一下一个JSP菜鸟如何开始分析tomcat源码的。下面进入正题:
我主要的参考资料是《深入剖析tomcat》的中文版,这个pdf可以在CSDN上免费下载到。这里我不想过多重复书中已经写得非常详细的内容,主要探讨一下filter和servlet的关系。当然首先还是搬运一下,下图描述了tomcat的方法调用序列。
具体过程如下:
(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自己弄的一个“傀儡皇帝”。后边继续研究研究。