最近在看《how tomcat works》。看完第6章,对整个时序流程还是感觉有点模糊,所以画了一个时序图总结下。
其中省略了一部分内容:
- 生命周期管理,事件发生调用fireLifecycleEvent,相关listener会有动作,省略了
- 管道的逐级调用省略了
Lifecycle
生命周期时间发生时,调用fireLifecycleEvent,被注册的listener会逐个触发,在listener内部检测事件类型,进行相应的处理,fireLifecycleEvent方法的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void fireLifecycleEvent(String type, Object data)
{
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = null;
synchronized (listeners) {
interested = (LifecycleListener[]) listeners.clone();
}
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
|
LifecycleListener在lifecycleEvent方法中对事件类型进行检查,并做出相应的响应。
Servlet的载入
Serlet的载入是在pipline的逐级调用中完成的。查看bootstrap的代码:
1 2 3 4 5 6 7 8 9 10 11
| Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");
|
可以看到Serlvlet跟SimpleWrapper相关,而SimpleWrapper的构造器有如下代码:
1 2 3 4 5 6 7
| public SimpleWrapper()
{
pipeline.setBasic(new SimpleWrapperValve());
}
|
可以看到SimpleWrapperValve被设置为基础阀。在查看SimpleWrapperValve的invoke方法代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {
SimpleWrapper wrapper = (SimpleWrapper) getContainer();
ServletRequest sreq = request.getRequest();
ServletResponse sres = response.getResponse();
Servlet servlet = null;
HttpServletRequest hreq = null;
if (sreq instanceof HttpServletRequest)
hreq = (HttpServletRequest) sreq;
HttpServletResponse hres = null;
if (sres instanceof HttpServletResponse)
hres = (HttpServletResponse) sres;
try {
servlet = wrapper.allocate();
if (hres!=null && hreq!=null) {
servlet.service(hreq, hres);
} else {
servlet.service(sreq, sres);
}
} catch (ServletException e) {
}
}
|
可以看到servlet的载入。
那么SimpleWrapperValve是怎么找到对应的Wrapper的呢?
从代码1
| SimpleWrapper wrapper = (SimpleWrapper) getContainer();
|
看到是调用getContainer方法得到的。而setContainer()发生在addValve和setBasic方法中。
值得一提的是,SimpleWrapperValve在SimpleWrapper的pipeline实例中被设置为基础阀,而SimpleContext的pipeline实例中对应的基础阀则是SimpleContextValve,在SimpleContextValve的invoke方法中有获取Wrapper实例的代码,正是这样实现的从Context调用的子容器Wrapper
SimpleWrapperValve的invoke方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {
if (!(request.getRequest() instanceof HttpServletRequest)
|| !(response.getResponse() instanceof HttpServletResponse))
{
return;
}
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
String contextPath = hreq.getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length()).toUpperCase();
Context context = (Context) getContainer();
Wrapper wrapper = null;
try {
wrapper = (Wrapper) context.map(request, true);
} catch (IllegalArgumentException e) {
badRequest(requestURI, (HttpServletResponse) response.getResponse());
return;
} if (wrapper == null)
{
notFound(requestURI, (HttpServletResponse) response.getResponse());
return;
}
response.setContext(context);
wrapper.invoke(request, response);
}
|
总结起来就是httpProcessor在process()方法中调用connector.getcontainer().invoke(),使得SimpleContext中的pipeline逐个调用阀,而SimpleContextValve这个基础阀调用了Wrapper,从而实现servlet的载入调用