來看看ContainerBase的start方法:
1
public 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進行處理??吹浆F在的感覺就是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方法
1
public 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要求的下一級對象,則整個處理過程也會立即結束。