来看看ContainerBase的start方法:
1public synchronized void start() throws LifecycleException {
2
3 //如果Container已经处于start状态,直接返回
4 if (started) {
5 if(log.isInfoEnabled())
6 log.info(sm.getString("containerBase.alreadyStarted", logName()));
7 return;
8 }
9
10 // Notify our interested LifecycleListeners
11 lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
12
13 started = true;
14
15 // Start our subordinate components, if any
16 if ((loader != null) && (loader instanceof Lifecycle))
17 ((Lifecycle) loader).start();
18 logger = null;
19 getLogger();
20 if ((logger != null) && (logger instanceof Lifecycle))
21 ((Lifecycle) logger).start();
22 //用来管理session
23 if ((manager != null) && (manager instanceof Lifecycle))
24 ((Lifecycle) manager).start();
25 //看名字就知道是干什么的,不过研究集群的优先级很低
26 if ((cluster != null) && (cluster instanceof Lifecycle))
27 ((Lifecycle) cluster).start();
28 //用来进行访问控制,或者权限控制的
29 if ((realm != null) && (realm instanceof Lifecycle))
30 ((Lifecycle) realm).start();
31 //和JNDI相关
32 if ((resources != null) && (resources instanceof Lifecycle))
33 ((Lifecycle) resources).start();
34
35 //启动所有子container
36 Container children[] = findChildren();
37 for (int i = 0; i < children.length; i++) {
38 if (children[i] instanceof Lifecycle)
39 ((Lifecycle) children[i]).start();
40 }
41
42 // 启动Container内部持有的pipeline对象,Container对Pipeline接口的实现就是通过调用这个内部持有的Pipeline对象
43 if (pipeline instanceof Lifecycle)
44 ((Lifecycle) pipeline).start();
45
46 // Notify our interested LifecycleListeners
47 lifecycle.fireLifecycleEvent(START_EVENT, null);
48
49 // 注释说这个函数用来check session是否过期,但看的不是太懂
50 threadStart();
51
52 // Notify our interested LifecycleListeners
53 lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
54
55}
56
所有和cluster、realm相关都放在最后来研究了,不管怎么样先把tomcat如何处理request的整个过程串起来对现在的我来说是最重要的。另外还有Tomcat中的很多部件都用到了JMX API,即SNMP的Java实现来进行性能检测和管理,这个也会放在最后研究。
ContainerBase就看这么多了,下面来看看StandardEngine这个类。除去和cluster、realm、JMX相关的方法后,StanderdEngine剩下的方法就很很少了。
StandardEngine有一个Service类型的成员。Java doc中指出Service就是由很多共享同一个Container的Connector组成。一个Service对应于一个Container,来自这个Service的任何一个Connector的request都会由其对应的Container进行处理。看到现在的感觉就是Connector对Container提供request对象,并接受Container返回的response对象。在Tomcat中有很多类别都被用来体现现request或者response,例如org.apache.catalina.connector .Request就是Coyote request的一个wrapper类,Coyote这个framework帮助封装了底层的网络复杂性,向上提供一个统一的接口。我想tomcat既能够成为一个standalone的http、jsp/Servlet服务器,也能够同apache http server集成,很可能就是依赖于Coyote提供的统一接口。
在构造函数中会将StandardEngine这个Pipeline的最后一个Valve,即Basic设置为StandardEngineValve。来看看StandardEnginValue的invoke方法
1public final void invoke(Request request, Response response)
2 throws IOException, ServletException {
3
4 // Select the Host to be used for this Request
5 Host host = request.getHost();
6 if (host == null) {
7 response.sendError
8 (HttpServletResponse.SC_BAD_REQUEST,
9 sm.getString("standardEngine.noHost",
10 request.getServerName()));
11 return;
12 }
13
14 // Ask this Host to process this request
15 host.getPipeline().getFirst().invoke(request, response);
16
17 }
18
可以看出在处理到StandardEngine这个Pipeline的最后一个Valve时,会根据当前request所指定的Host,将当前的request和response传递给该Host这个Pipeline的第一个Valve进行处理。
我想Tomcat中的Engine、Host、Context、Wrapper处理request生成response的过程大概是这样的:
Engine在收到request后在其Pipeline中的每一个Valve对request进行处理,也可能会生成response的某些部分,在最后一个Valve中将request和response传给下一级Container即Host的第一个Valve。Host重复同样过程,继续传递给Context,Context再传递给Wrapper。由于Wrapper代表的是Servlet对象,因此在Wrapper处所有的处理都结束了,response对象生成完毕。当然了,如果在某一级中无法找到request要求的下一级对象,则整个处理过程也会立即结束。