基于tomcat 5.0.28
以下是一個連接從被connector接受知道被處理所經(jīng)過的幾個步驟,其中無關(guān)代碼已省略。其中的每個方法都標(biāo)有全名,可以直接去類中查找。
[noten]代表下面的note, 如[note1],[note2].
(n) 代表第幾步,如(4) 代表第4個處理步驟 4.在CoyoteAdapter中,將connector 與 container 相關(guān)聯(lián)
$$代表作者的注釋
1. 接受一個新的連接請求
void org.apache.tomcat.util.net.TcpWorkerThread.runIt(Object[] perThrData){
Socket s = null;
try {
s = endpoint.acceptSocket();
} finally {
// Continue accepting on another thread...
if (endpoint.isRunning()) {
endpoint.tp.runIt(this); $$此處啟動另一個TcpWorkerTread去接受其他請求,此線程處理已接受的請求
}
}
TcpConnection con = null;
con = (TcpConnection) perThrData[0];
con.setEndpoint(endpoint);
con.setSocket(s);
endpoint.getConnectionHandler().processConnection(con,(Object[]) perThrData[1]);
}
2.新接收的請求被傳到Http11ConnectionHandler中處理。
void org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler.processConnection(TcpConnection connection, Object[] thData){
Http11Processor processor=null;
processor=(Http11Processor)thData[Http11Protocol.THREAD_DATA_PROCESSOR]; $$[note1] 為什么 thData[Http11Protocol.THREAD_DATA_PROCESSOR] 會是 Http11Processor 的一個實(shí)例.
socket=connection.getSocket();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
processor.setSocket( socket );
processor.process(in, out); $$ processor 是 org.apache.coyote.http11.Http11Processor 的 一個實(shí)例
}
3.在 Http11Processor 中處理 http11 協(xié)議相關(guān)的信息
void org.apache.coyote.http11.Http11Processor.process(InputStream input, OutputStream output) throws IOException{
inputBuffer.setInputStream(input);
outputBuffer.setOutputStream(output);
inputBuffer.parseHeaders(); $$ http11 協(xié)議頭在此方法中被取出
adapter.service(request, response); $$ adapter 是 org.apache.coyote.tomcat5.CoyoteAdapter 的 一個實(shí)例
}
4.在CoyoteAdapter中,將connector 與 container 相關(guān)聯(lián)
void org.apache.coyote.tomcat5.CoyoteAdapter.service(Request req, Response res) throws Exception{
$$ 底層使用的org.apache.coyote.Request,org.apache.coyote.Response 在此處被轉(zhuǎn)換成
$$ org.apache.coyote.tomcat5.CoyoteRequest 和 org.apache.coyote.tomcat5.CoyoteResponse
$$ 二者都分別實(shí)現(xiàn)了 javax.servlet.http.HttpServletRequest 和 javax.servlet.http.HttpServletResponse
request = (CoyoteRequest) connector.createRequest();
request.setCoyoteRequest(req);
response = (CoyoteResponse) connector.createResponse();
response.setCoyoteResponse(res);
// Create objects
request = (CoyoteRequest) connector.createRequest();
request.setCoyoteRequest(req);
response = (CoyoteResponse) connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
request.setResponse(response);
response.setRequest(request);
// Parse and set Catalina and configuration specific
// request parameters
if ( postParseRequest(req, request, res, response) ) {
$$ 在 postParseRequest() 方法中, 與此request相關(guān)聯(lián)的 context 和 wrapper 對象被找出,并與此 request 關(guān)聯(lián)
$$
$$ // Request mapping.
$$ connector.getMapper().map(req.serverName(), decodedURI,request.getMappingData());
$$ request.setContext((Context) request.getMappingData().context);
$$ request.setWrapper((Wrapper) request.getMappingData().wrapper);
$$$$$$$$$$$$$$$$$$$$
$$ 注意!! 此下所有的 request 和 response 對象都是 org.apache.coyote.tomcat5.CoyoteRequest 和 org.apache.coyote.tomcat5.CoyoteResponse 類的實(shí)例,
$$ 而不是org.apache.coyote.Request,org.apache.coyote.Response 類的實(shí)例
// Calling the container
connector.getContainer().invoke(request, response); $$此處connector.getContainer() 取到的是org.apache.catalina.core.StandardEngine類的實(shí)例
}
}
5.request 和 response 被傳送到 container 中處理
void org.apache.catalina.core.ContainerBase.invoke(Request request, Response response) throws IOException, ServletException{
$$ 下面的 pipleline StandardPineLine 的一個實(shí)例
$$ 在這個類的實(shí)現(xiàn)中,有這樣一行代碼
$$ protected Pipeline pipeline = new StandardPipeline(this);
pipeline.invoke(request, response);
}
6.request 和 response 在 Container 的pipleline 中處理
void org.apache.catalina.core.StandardPipeline.invoke(Request request, Response response) throws IOException, ServletException{
StandardValveContext valveContext =
(StandardValveContext) request.getValveContext();
if (valveContext == null) {
valveContext = new StandardValveContext();
request.setValveContext(valveContext);
}
valveContext.set(basic, valves);
valveContext.invokeNext(request, response);
valveContext.set(null, null);
}
7.調(diào)用container 的 pipeline 中的 第一個valve
void org.apache.catalina.core.StandardValveContext.invokeNext(Request request, Response response) throws IOException, ServletException {
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this); $$ 此處只有一個basic valve, 所以此處的代碼不執(zhí)行。
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 代碼執(zhí)行到此處,basic 是 org.apache.catalina.core.StandardEngineValve 類的一個實(shí)例
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
8.執(zhí)行 engine 的 valve
void org.apache.catalina.core.StandardEngineValve.invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException
// Select the Host to be used for this Request
Host host = request.getHost(); $$[note3] host 如何得到?
if (host == null) {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHost",
request.getRequest().getServerName()));
return;
}
// Ask this Host to process this request
host.getPipeline().invoke(request, response); $$ 此處的pipleline 是 org.apache.catalina.core.StandardPipeline 類的一個實(shí)例
}
9. 調(diào)用 host 的 pipeline
void org.apache.catalina.core.StandardPipeline.invoke(Request request, Response response) throws IOException, ServletException{
StandardValveContext valveContext =
(StandardValveContext) request.getValveContext();
if (valveContext == null) {
valveContext = new StandardValveContext();
request.setValveContext(valveContext);
}
valveContext.set(basic, valves);
valveContext.invokeNext(request, response);
valveContext.set(null, null);
}
10. 調(diào)用 host 中的 valve
void org.apache.catalina.core.StandardValveContext.invokeNext(Request request, Response response) throws IOException, ServletException {
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this); $$ 此處先調(diào)用一個 errorreportvalve,它是host中的valve,而且不是basic valve
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 此處不執(zhí)行
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
11. 調(diào)用 host 的 pipeline 中的 errorreprotvalve
void org.apache.catalina.valves.ErrorReportValve.invoke(Request request, Response response,ValveContext context) throws IOException, ServletException
context.invokeNext(request, response); $$ 此方法的第一行就調(diào)用host 中的其他valve接著處理request
$$ 下面是錯誤處理的代碼,省略
}
12. 調(diào)用 host 的 pipeline 中的下一個valve
void org.apache.catalina.core.StandardValveContext.invokeNext(Request request, Response response) throws IOException, ServletException {
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this); $$ there is only two valve's in this context, one the errorreportvalve, which has been invoked in (11), so program dose not run to here
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ program runs here, basic is an instance of StandardHostValve
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
13. 調(diào)用 host 的 pipeline 中的 StandardHostValve
void org.apache.catalina.core.StandardHostValve.invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException{
Context context = request.getContext(); $$ context 是 org.apache.catalina.core.StandardContext 類的一個實(shí)例
context.getPipeline().invoke(request, response); $$ pipeline 是 org.apache.catalina.core.StandardPipeline 類的一個實(shí)例
}
14. 調(diào)用 context 的 pipeline 中的 Valve
void org.apache.catalina.core.StandardPipeline.invoke(Request request, Response response) throws IOException, ServletException{
StandardValveContext valveContext =
(StandardValveContext) request.getValveContext();
if (valveContext == null) {
valveContext = new StandardValveContext();
request.setValveContext(valveContext);
}
valveContext.set(basic, valves);
valveContext.invokeNext(request, response);
valveContext.set(null, null);
}
15.調(diào)用 context 的 pipeline 中的下一個 Valve
void org.apache.catalina.core.StandardValveContext.invokeNext(Request request, Response response) throws IOException, ServletException {
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this); $$ standcontext 的 pipeline中 只有一個basic valve, 所以此處不執(zhí)行
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 程序執(zhí)行到此處, basic 是 org.apache.catalina.core.StandardContextValve 的一個實(shí)例
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
16. 執(zhí)行 context 的 pipeline 中的 Valve
void org.apache.catalina.core.StandardContextValve.invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException{
HttpRequest hreq = (HttpRequest) request;
MessageBytes requestPathMB = hreq.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) $$從這里可知, 為什么http請求無法訪問web-inf目錄下面的內(nèi)容
|| (requestPathMB.equalsIgnoreCase("/META-INF"))
|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
String requestURI = hreq.getDecodedRequestURI();
notFound(requestURI, (HttpServletResponse) response.getResponse());
return;
}
Wrapper wrapper = request.getWrapper(); $$ wrapper從那里得到,見(4)中的注釋
invokeInternal(wrapper, request, response);
}
17 StandardContextValve中繼續(xù)處理request 和 response
void org.apache.catalina.core.StandardContextValve.invokeInternal(Wrapper wrapper, Request request, Response response) throws IOException, ServletException{
wrapper.getPipeline().invoke(request, response); $$ wrapper 是 org.apache.catalina.core.StandardWrapper 類的一個實(shí)例
$$ pipeline 是 org.apache.catalina.core.StandardPipeline 類的一個實(shí)例
}
18.執(zhí)行 wrapper 的 pipleline
void org.apache.catalina.core.StandardPipeline.invoke(Request request, Response response) throws IOException, ServletException{
StandardValveContext valveContext =
(StandardValveContext) request.getValveContext();
if (valveContext == null) {
valveContext = new StandardValveContext();
request.setValveContext(valveContext);
}
valveContext.set(basic, valves);
valveContext.invokeNext(request, response);
valveContext.set(null, null);
}
19. 執(zhí)行 wrapper 的 pipeline 中的valve
void org.apache.catalina.core.StandardValveContext.invokeNext(Request request, Response response) throws IOException, ServletException {
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this); $$ wrapper 的 pipeline中只有一個basic valve,此處代碼不執(zhí)行
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 程序執(zhí)行到此處,basic 是 org.apache.catalina.core.StandardWrapperValve 的一個實(shí)例
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
20. 執(zhí)行 standardwrapervalve,此處將會執(zhí)行 servlet.service() 方法
void org.apache.catalina.core.StandardWrapperValve.invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException{
Servlet servlet = null;
HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); $$ org.apache.catalina.Request 被封裝成 javax.servlet.http.HttpServletRequest.
HttpServletResponse hres =(HttpServletResponse) response.getResponse(); $$ org.apache.catalina.Response 被封裝成 javax.servlet.http.HttpServletResponse.
servlet = wrapper.allocate(); $$[note4] servlet 是如何被找到并裝載的
if ((servlet != null) && (filterChain != null)) {
filterChain.doFilter(hreq, hres); $$調(diào)用此servlet的filterchain
}
21. 調(diào)用servlet 的 filterchain 處理 request 和 response
void org.apache.catalina.core.ApplicationFilterChain.doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException{
internalDoFilter(request,response);
}
22. 調(diào)用servlet 的 filterchain 處理 request 和 response
void org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException{
$$ 此處省略filter 處理的代碼,filter 被一個一個調(diào)用。
$$ 如果http請求的是一個jsp頁面, 下面的 servlet 會是 org.apache.jasper.servlet.JspServlet 類的一個實(shí)例
$$ 若是 html 頁面, 下面的 servlet 會是 org.apache.catalina.servlets.DefaultServlet 類的一個實(shí)例
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse)) {
servlet.service((HttpServletRequest) request, (HttpServletResponse) response);
servlet.service(request, response);
} else {
servlet.service(request, response);
}
}
$$[note1] 為什么 thData[Http11Protocol.THREAD_DATA_PROCESSOR] 會是 Http11Processor 的一個實(shí)例,是在那里被賦值的?
下面的代碼可以說明
Object[] org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler.init(){
Http11Processor processor = new Http11Processor(proto.maxHttpHeaderSize);
thData[Http11Protocol.THREAD_DATA_PROCESSOR]=processor;
return thData;
}
Object[] org.apache.tomcat.util.net.TcpWorkerThread.getInitData(){
// no synchronization overhead, but 2 array access
Object obj[]=new Object[2];
obj[1]= endpoint.getConnectionHandler().init();
obj[0]=new TcpConnection();
return obj;
}
void org.apache.tomcat.util.threads.ThreadPool.ControlRunnable.run(){
Object thData[] = _toRun.getInitData();
t.setThreadData(p, thData);
_toRun.runIt(t.getThreadData(p)); $$此處是(1)中的 runIt(Object[] perThrData) perThrData的來歷
}
$$[note3] host 是如何得到了?
Host host = request.getHost() 此處的 request 實(shí)際上是 CoyoteRequest 類的一個實(shí)例
它是這樣實(shí)現(xiàn)的:
public Host CoyoteRequest.getHost() {
if (getContext() == null)
return null;
return (Host) getContext().getParent(); $$ 此處,host 是從與此request相關(guān)的context中得到的,
//return ((Host) mappingData.host); $$ 那么 context 又是如何得到的呢?見(4)中的注釋
}
$$[note4] servlet 是如何被找到并裝載的, SingleTreadPool 模型是如何實(shí)現(xiàn)的?
Servlet org.apache.catalina.core.StandardWrapper.allocate() throws ServletException{
if (singleThreadModel==false) {
// Load and initialize our instance if necessary
if (instance == null) {
synchronized (this) {
if (instance == null) {
try {
instance = loadServlet();
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
}
}
}
}
return (instance); $$如果servlet沒有實(shí)現(xiàn)SingleTreadModel,每次都返回同一個servlet實(shí)例
}
synchronized (instancePool) { $$如果servlet 實(shí)現(xiàn)了SingleTreadModel, 程序執(zhí)行到此處
while (countAllocated >= nInstances) {
// Allocate a new instance if possible, or else wait
if (nInstances < maxInstances) {
instancePool.push(loadServlet()); $$此處用一個棧來保存servlet實(shí)例
nInstances++;
} else {
instancePool.wait();
}
}
countAllocated++;
return (Servlet) instancePool.pop();
}
}
Servlet org.apache.catalina.core.StandardWrapper.loadServlet() throws ServletException{
Servlet servlet;
String actualClass = servletClass; $$ 對于靜態(tài)html頁面來說,此處是 org.apache.catalina.servlets.DefaultServlet
$$ 對于 jsp 頁面來說,此處是 org.apache.jasper.servlet.JspServlet
Class classClass = null;
classClass = classLoader.loadClass(actualClass);
servlet = (Servlet) classClass.newInstance();
servlet.init(facade);
}
一般來講,一個簡單的catalina實(shí)現(xiàn)就是最頂層一個server, 之后是一個service,其中包括兩個結(jié)構(gòu)上并列的的組件,connctor,和engine.(connector 接受請求,engine處理請求). engine 下面是Host, Host 下面是 Context, Context下面是Wrapper,最下面是 servlet.
一般來講,一個http request在被connector接受之后,傳到container中被處理。處理的過程簡言之就是依次調(diào)用各個catalina container的valve. 先是engine的valve,再是host, context,wrapper,然后是servlet的filter, 最后是servlet.service()