最近在看《how tomcat works》。看完第6章,对整个时序流程还是感觉有点模糊,所以画了一个时序图总结下。
其中省略了一部分内容:
- 生命周期管理,事件发生调用fireLifecycleEvent,相关listener会有动作,省略了
管道的逐级调用省略了
Lifecycle生命周期时间发生时,调用fireLifecycleEvent,被注册的listener会逐个触发,在listener内部检测事件类型,进行相应的处理,fireLifecycleEvent方法的代码如下:
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的代码:
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");{% endcodeblock %}
可以看到Serlvlet跟SimpleWrapper相关,而SimpleWrapper的构造器有如下代码:
public SimpleWrapper()
{
pipeline.setBasic(new SimpleWrapperValve());
}
可以看到SimpleWrapperValve被设置为基础阀。在查看SimpleWrapperValve的invoke方法代码:
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;
// Allocate a servlet instance to process this request
try {
servlet = wrapper.allocate();
if (hres!=null && hreq!=null) {
servlet.service(hreq, hres);
} else {
servlet.service(sreq, sres);
}
} catch (ServletException e) {
}
}
可以看到servlet的载入。
那么SimpleWrapperValve是怎么找到对应的Wrapper的呢?
从代码SimpleWrapper wrapper = (SimpleWrapper) getContainer(); 看到是调用getContainer方法得到的。而setContainer()发生在addValve和setBasic方法中。
值得一提的是,SimpleWrapperValve在SimpleWrapper的pipeline实例中被设置为基础阀,而SimpleContext的pipeline实例中对应的基础阀则是SimpleContextValve,在SimpleContextValve的invoke方法中有获取Wrapper实例的代码,正是这样实现的从Context调用的子容器Wrapper
SimpleWrapperValve的invoke方法如下:
public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {
// Validate the request and response object types
if (!(request.getRequest() instanceof HttpServletRequest)
|| !(response.getResponse() instanceof HttpServletResponse))
{
return;
// NOTE - Not much else we can do generically
}
// Disallow any direct access to resources under WEB-INF or META-INF
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();
// Select the Wrapper to be used for this Request
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;
}
// Ask this Wrapper to process this Request
response.setContext(context);
wrapper.invoke(request, response);
}
总结起来就是httpProcessor在process()方法中调用connector.getcontainer().invoke(),使得SimpleContext中的pipeline逐个调用阀,而SimpleContextValve这个基础阀调用了Wrapper,从而实现servlet的载入调用