#tomcat#启动过程分析(下)
如何将连接放入容器
connector.getContainer()得到的容器应该是StandardEngine,StandardEngine没有invoke方法,它继承于ContainerBase,ContainerBase的invoke方法是传递到Pipeline,调用了Pipeline的invoke方法。Pipeline是一个管道类,每一个管道类Pipeline包含数个阀类,阀类是实现了Valve接口的类,Valve接口声明了invoke方法。
管道和阀的概念跟servlet编程里面的过滤器机制非常像,管道就像过滤器链,阀就好比是过滤器。不过管道中还有一个基础阀的概念,所谓基础阀就是在管道中当管道把所有的普通阀都调用完成后再调用的。在tomcat中,当调用了管道的invoke方法,管道则会顺序调用它里面的阀的invoke方法。在调用普通阀的invoke方法时,会把内部类StandardPipelineValveContext本身传进去,这样在普通阀中就能调用invokeNext方法以便访问下一个阀的invoke方法。
调用完普通阀数组valves的阀后,开始调用基础阀basic的invoke方法在每一个容器的构造函数类就已经初始化了基础阀,在容器构造的时候就已经把基础阀添加进管道pipeline中。在StandardEngine的基础阀StandardEngineValve里,调用了子容器StandardHost的invoke方法,利的传递到子容器StandardHost的invoke方法,变成了StandardHost.invoke(request, response)。StandardHost也会传递给它的子容器,最后传递到最小的容器StandardWrapper的invoke方法,然后调用StandardWrapper的基础阀StandardWrapperValue的invoke方法,由于StandardWrapper是最小的容器了,不能再传递到其他容器的invoke方法了,它的invoke方法主要做了两件事,
1:创建一个过滤器链
2:分配一个servlet或者jsp。
通过servlet =wrapper.allocate(); 进入StandardWrapper的allocate方法,allocate主要就是调用了loadServlet方法,在loadServlet方法类用tomcat自己的类加载器实例化了一个servlet对象,并调用了该servlet的init和service方法。
在这这责任链之中StandardHostValue调用了standardContext,web应用中的Servlet、Listener、Filter的实例使用StandardContext类的startInternal方法构造出来。如果使用Spring、struts则需要分别配置ContextLoaderListener和StrutsPrepareAndExecuteFilter。
ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
Engine 和 Host 处理请求的时序图
Context 和 wrapper 的处理请求时序图
总结:Tomcat Server处理一个http请求的过程
假设来自客户的请求为:
http://localhost:8080/wsota/wsota_index.jsp
1) 请求被发送到本机端口8080,被在那里侦听的CoyoteHTTP/1.1 Connector获得
2)Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
3) Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host
4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
5)localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context
6) Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为”"的Context去处理)
7) path=”/wsota”的Context获得请求/wsota_index.jsp,在它的mappingtable中寻找对应的servlet
8)Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
10)Context把执行完了之后的HttpServletResponse对象返回给Host
11)Host把HttpServletResponse对象返回给Engine
12)Engine把HttpServletResponse对象返回给Connector
13)Connector把HttpServletResponse对象返回给客户browser