本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996
目标:在这篇文章希望搞明白
connector.getContainer().invoke(request, response);
调用容器的invoke后是怎么传递到 servlet或者jsp的?
由上篇文章
Tomcat源码分析(三)--连接器是如何与容器关联的?
可知,
connector.getContainer()得到的容器应该是
StandardEngine(其实应该是由server.xml文件配置得到的,这里先假定是
StandardEngine
),
StandardEngine没有invoke方法,它继承与ContainerBase(事实上所有的容器都继承于ContainerBase,在ContainerBase类有一些容器的公用方法和属性),抽象类
ContainerBase
的invoke方法如下:
由代码可知 ContainerBase 的invoke方法是传递到Pipeline,调用了Pipeline的invoke方法。这里要说一下Pipeline这个类,这是一个管道类,每一个管道类 Pipeline 包含数个阀类,阀类是实现了Valve接口的类,Valve接口声明了invoke方法。管道和阀的概念跟servlet编程里面的过滤器机制非常像, 管道就像过滤器链,阀就好比是过滤器 。不过管道中还有一个基础阀的概念,所谓基础阀就是在管道中当管道把所有的普通阀都调用完成后再调用的。不管是普通阀还是基础阀,都实现了Value接口,也都继承于抽象类ValveBase。在tomcat中,当调用了管道的invoke方法,管道则会顺序调用它里面的阀的invoke方法。先看看管道StandardPipeline的invoke方法:
其中StandardPipelineValveContext是管道里的一个内部类,内部类的作用是帮助管道顺序调用阀Value的invoke方法,下面看它的定义代码:
内部类 StandardPipelineValveContext的invokeNext方法通过使用局部变量来访问下一个管道数组,管道类的变量stage保存当前访问到第几个阀,valves保存管道的所有阀, 在调用普通阀的invoke方法是,会把内部类 StandardPipelineValveContext本身传进去,这样在普通阀中就能调用invokeNext方法以便访问下一个阀的invoke方法 ,下面 看一个普通阀的invoke方法:
这个阀的invoke方法,通过传进来到 StandardPipelineValveContext(实现了ValveContext接口 )的invokeNext方法来实现调用下一个阀的invoke方法。然后简单的打印了请求的ip地址。
最后再看
StandardPipelineValveContext的invokeNext方法,调用完普通阀数组valves的阀后,开始调用基础阀basic的
invoke方法,这里先说基础阀的初始化,在每一个容器的构造函数类就已经初始化了基础阀,看容器StandardEngine的构造函数:
这里省略了很多代码,主要是为了更加理解调用逻辑,在StandardEngine的基础阀StandardEngineValve里,调用了子容器invoke方法(这里子容器就是StandardHost), 还记得一开始connector.invoke(request, response)(即StandardEngine的invoke方法)现在顺利的传递到子容器StandardHost的invoke方法,变成了StandardHost.invoke(request, response)。 由此可以猜测StandardHost也会传递给它的子容器,最后传递到最小的容器StandardWrapper的invoke方法,然后调用StandardWrapper的基础阀StandardWrapperValue的invoke方法,由于StandardWrapper是最小的容器了,不能再传递到其他容器的invoke方法了,那它的invoke方法做了什么?主要做了两件事, 1:创建一个过滤器链并 2:分配一个servlet或者jsp,主要代码如下:
这里先不关注jsp,只关注一下servlet,通过servlet = wrapper.allocate(); 进入StandardWrapper的allocate方法,allocate主要就是调用了loadServlet方法,在loadServlet方法类用tomcat自己的类加载器实例化了一个servlet对象,并调用了该servlet的init和service方法:
至此已经把请求传递到servlet的service(或者jsp的service)方法,整个处理请求到这里就结束了,剩下的就是返回客户端了。这里提出几个问题。 1:那么多的servlet,tomcat是怎么知道要请求到哪个servlet? 这个问题留待下篇博客再来讲吧。