基于tomcat 5.0.28
以下是一个连接从被connector接受知道被处理所经过的几个步骤,其中无关代码已省略。其中的每个方法都标有全名,可以直接去类中查找。
[noten]代表下面的note, 如[note1],[note2].
(n) 代表第几步,如(4) 代表第4个处理步骤 4.在CoyoteAdapter中,将connector 与 container 相关联
$$代表作者的注释
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 的一个实例.
socket=connection.getSocket();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
processor.setSocket( socket );
processor.process(in, out); $$ processor 是 org.apache.coyote.http11.Http11Processor 的 一个实例
}
3.在 Http11Processor 中处理 http11 协议相关的信息
void org.apache.coyote.http11.Http11Processor.process(InputStream input, OutputStream output) throws IOException{
inputBuffer.setInputStream(input);
outputBuffer.setOutputStream(output);
inputBuffer.parseHeaders(); $$ http11 协议头在此方法中被取出
adapter.service(request, response); $$ adapter 是 org.apache.coyote.tomcat5.CoyoteAdapter 的 一个实例
}
4.在CoyoteAdapter中,将connector 与 container 相关联
void org.apache.coyote.tomcat5.CoyoteAdapter.service(Request req, Response res) throws Exception{
$$ 底层使用的org.apache.coyote.Request,org.apache.coyote.Response 在此处被转换成
$$ org.apache.coyote.tomcat5.CoyoteRequest 和 org.apache.coyote.tomcat5.CoyoteResponse
$$ 二者都分别实现了 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相关联的 context 和 wrapper 对象被找出,并与此 request 关联
$$
$$ // 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 类的实例,
$$ 而不是org.apache.coyote.Request,org.apache.coyote.Response 类的实例
// Calling the container
connector.getContainer().invoke(request, response); $$此处connector.getContainer() 取到的是org.apache.catalina.core.StandardEngine类的实例
}
}
5.request 和 response 被传送到 container 中处理
void org.apache.catalina.core.ContainerBase.invoke(Request request, Response response) throws IOException, ServletException{
$$ 下面的 pipleline StandardPineLine 的一个实例
$$ 在这个类的实现中,有这样一行代码
$$ 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.调用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, 所以此处的代码不执行。
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 代码执行到此处,basic 是 org.apache.catalina.core.StandardEngineValve 类的一个实例
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
8.执行 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 类的一个实例
}
9. 调用 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. 调用 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); $$ 此处先调用一个 errorreportvalve,它是host中的valve,而且不是basic valve
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 此处不执行
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
11. 调用 host 的 pipeline 中的 errorreprotvalve
void org.apache.catalina.valves.ErrorReportValve.invoke(Request request, Response response,ValveContext context) throws IOException, ServletException
context.invokeNext(request, response); $$ 此方法的第一行就调用host 中的其他valve接着处理request
$$ 下面是错误处理的代码,省略
}
12. 调用 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. 调用 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 类的一个实例
context.getPipeline().invoke(request, response); $$ pipeline 是 org.apache.catalina.core.StandardPipeline 类的一个实例
}
14. 调用 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.调用 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, 所以此处不执行
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 程序执行到此处, basic 是 org.apache.catalina.core.StandardContextValve 的一个实例
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
16. 执行 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目录下面的内容
|| (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中继续处理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 类的一个实例
$$ pipeline 是 org.apache.catalina.core.StandardPipeline 类的一个实例
}
18.执行 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. 执行 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,此处代码不执行
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this); $$ 程序执行到此处,basic 是 org.apache.catalina.core.StandardWrapperValve 的一个实例
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
20. 执行 standardwrapervalve,此处将会执行 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); $$调用此servlet的filterchain
}
21. 调用servlet 的 filterchain 处理 request 和 response
void org.apache.catalina.core.ApplicationFilterChain.doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException{
internalDoFilter(request,response);
}
22. 调用servlet 的 filterchain 处理 request 和 response
void org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException{
$$ 此处省略filter 处理的代码,filter 被一个一个调用。
$$ 如果http请求的是一个jsp页面, 下面的 servlet 会是 org.apache.jasper.servlet.JspServlet 类的一个实例
$$ 若是 html 页面, 下面的 servlet 会是 org.apache.catalina.servlets.DefaultServlet 类的一个实例
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 的一个实例,是在那里被赋值的?
下面的代码可以说明
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 实际上是 CoyoteRequest 类的一个实例
它是这样实现的:
public Host CoyoteRequest.getHost() {
if (getContext() == null)
return null;
return (Host) getContext().getParent(); $$ 此处,host 是从与此request相关的context中得到的,
//return ((Host) mappingData.host); $$ 那么 context 又是如何得到的呢?见(4)中的注释
}
$$[note4] servlet 是如何被找到并装载的, SingleTreadPool 模型是如何实现的?
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没有实现SingleTreadModel,每次都返回同一个servlet实例
}
synchronized (instancePool) { $$如果servlet 实现了SingleTreadModel, 程序执行到此处
while (countAllocated >= nInstances) {
// Allocate a new instance if possible, or else wait
if (nInstances < maxInstances) {
instancePool.push(loadServlet()); $$此处用一个栈来保存servlet实例
nInstances++;
} else {
instancePool.wait();
}
}
countAllocated++;
return (Servlet) instancePool.pop();
}
}
Servlet org.apache.catalina.core.StandardWrapper.loadServlet() throws ServletException{
Servlet servlet;
String actualClass = servletClass; $$ 对于静态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实现就是最顶层一个server, 之后是一个service,其中包括两个结构上并列的的组件,connctor,和engine.(connector 接受请求,engine处理请求). engine 下面是Host, Host 下面是 Context, Context下面是Wrapper,最下面是 servlet.
一般来讲,一个http request在被connector接受之后,传到container中被处理。处理的过程简言之就是依次调用各个catalina container的valve. 先是engine的valve,再是host, context,wrapper,然后是servlet的filter, 最后是servlet.service()