How Tomcat Works(六)
本文继续分析HttpProcessor类,该类实现了org.apache.catalina.Lifecycle接口和java.lang.Runnable接口
我们先分析它的构造函数
/**
* The HttpConnector with which this processor is associated.
*/
private HttpConnector connector = null; /**
* The HTTP request object we will pass to our associated container.
*/
private HttpRequestImpl request = null; /**
* The HTTP response object we will pass to our associated container.
*/
private HttpResponseImpl response = null; /**
* Construct a new HttpProcessor associated with the specified connector.
*
* @param connector HttpConnector that owns this processor
* @param id Identifier of this HttpProcessor (unique per connector)
*/
public HttpProcessor(HttpConnector connector, int id) { super();
this.connector = connector;
this.debug = connector.getDebug();
this.id = id;
this.proxyName = connector.getProxyName();
this.proxyPort = connector.getProxyPort();
this.request = (HttpRequestImpl) connector.createRequest();
this.response = (HttpResponseImpl) connector.createResponse();
this.serverPort = connector.getPort();
this.threadName =
"HttpProcessor[" + connector.getPort() + "][" + id + "]"; }
构造函数用于初始化成员变量HttpConnector connector = null、HttpRequestImpl request = null、HttpResponseImpl response = null等
当调用它的start()方法时,用于启动处理器线程
/**
* Start the background thread we will use for request processing.
*
* @exception LifecycleException if a fatal startup error occurs
*/
public void start() throws LifecycleException { if (started)
throw new LifecycleException
(sm.getString("httpProcessor.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true; threadStart(); }
调用threadStart()方法
/**
* Start the background processing thread.
*/
private void threadStart() { log(sm.getString("httpProcessor.starting")); thread = new Thread(this, threadName);
thread.setDaemon(true);
thread.start(); if (debug >= 1)
log(" Background thread has been started"); }
即启动处理器线程,下面是run()方法
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
public void run() { // Process requests until we receive a shutdown signal
while (!stopped) { // Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue; // Process the request from this socket
try {
process(socket);
} catch (Throwable t) {
log("process.invoke", t);
} // Finish up this request
connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
} }
下面关键是分析await()方法与assign()方法是怎么同步的了,这里可以理解为经典的生产者与消费者模型
我们先来看assign()方法
/**
* Process an incoming TCP/IP connection on the specified socket. Any
* exception that occurs during processing must be logged and swallowed.
* <b>NOTE</b>: This method is called from our Connector's thread. We
* must assign it to our own thread so that multiple simultaneous
* requests can be handled.
*
* @param socket TCP socket to process
*/
synchronized void assign(Socket socket) { // Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
} // Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll(); if ((debug >= 1) && (socket != null))
log(" An incoming request is being assigned"); }
成员变量默认为boolean available = false
下面是await()方法
/**
* Await a newly assigned Socket from our Connector, or <code>null</code>
* if we are supposed to shut down.
*/
private synchronized Socket await() { // Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
} // Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll(); if ((debug >= 1) && (socket != null))
log(" The incoming request has been awaited"); return (socket); }
显然这里是采用notifyAll()方法与wait()方法相同通信,当await()方法执行notifyAll()并返回socket后,assign()方法又可以继续接收请求socket对象了
await()方法里面采用的是局部变量,为了不占用成员变量引用(Socket socket = null),返回的socket对象供处理器线程进行处理,又要回到run()方法了
Socket socket = await()这里也是采用了局部变量,与await()方法里面采用局部变量同样的原因
获取socket实例后,调用process()方法进行处理,处理完毕后将处理器对象重新入栈,最后是如果收到停止处理器线程命令,则事件通知可以停止线程了
下面关键是process()方法,这个方法有点长
/**
* Process an incoming HTTP request on the Socket that has been assigned
* to this Processor. Any exceptions that occur during processing must be
* swallowed and dealt with.
*
* @param socket The socket on which we are connected to the client
*/
private void process(Socket socket) {
boolean ok = true;
boolean finishResponse = true;
SocketInputStream input = null;
OutputStream output = null; // Construct and initialize the objects we will need
try {
input = new SocketInputStream(socket.getInputStream(),
connector.getBufferSize());
} catch (Exception e) {
log("process.create", e);
ok = false;
} keepAlive = true; while (!stopped && ok && keepAlive) { finishResponse = true; try {
request.setStream(input);
request.setResponse(response);
output = socket.getOutputStream();
response.setStream(output);
response.setRequest(request);
((HttpServletResponse) response.getResponse()).setHeader
("Server", SERVER_INFO);
} catch (Exception e) {
log("process.create", e);
ok = false;
} // Parse the incoming request
try {
if (ok) { parseConnection(socket);
parseRequest(input, output);
if (!request.getRequest().getProtocol()
.startsWith("HTTP/0"))
parseHeaders(input);
if (http11) {
// Sending a request acknowledge back to the client if
// requested.
ackRequest(output);
// If the protocol is HTTP/1.1, chunking is allowed.
if (connector.isChunkingAllowed())
response.setAllowChunking(true);
} }
} catch (EOFException e) {
// It's very likely to be a socket disconnect on either the
// client or the server
ok = false;
finishResponse = false;
} catch (ServletException e) {
ok = false;
try {
((HttpServletResponse) response.getResponse())
.sendError(HttpServletResponse.SC_BAD_REQUEST);
} catch (Exception f) {
;
}
} catch (InterruptedIOException e) {
if (debug > 1) {
try {
log("process.parse", e);
((HttpServletResponse) response.getResponse())
.sendError(HttpServletResponse.SC_BAD_REQUEST);
} catch (Exception f) {
;
}
}
ok = false;
} catch (Exception e) {
try {
log("process.parse", e);
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_BAD_REQUEST);
} catch (Exception f) {
;
}
ok = false;
} // Ask our Container to process this request
try {
((HttpServletResponse) response).setHeader
("Date", FastHttpDateFormat.getCurrentDate());
if (ok) {
connector.getContainer().invoke(request, response);
}
} catch (ServletException e) {
log("process.invoke", e);
try {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (Exception f) {
;
}
ok = false;
} catch (InterruptedIOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
try {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (Exception f) {
;
}
ok = false;
} // Finish up the handling of the request
if (finishResponse) {
try {
response.finishResponse();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
request.finishRequest();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
if (output != null)
output.flush();
} catch (IOException e) {
ok = false;
}
} // We have to check if the connection closure has been requested
// by the application or the response stream (in case of HTTP/1.0
// and keep-alive).
if ( "close".equals(response.getHeader("Connection")) ) {
keepAlive = false;
} // End of request processing
status = Constants.PROCESSOR_IDLE; // Recycling the request and the response objects
request.recycle();
response.recycle(); } try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log("process.invoke", e);
}
socket = null; }
上面方法中,首先根据参数socket的输入流与输出流初始化request对象与response对象,接着是解析输入流并填充request对象和response对象,接下来调用容器对象的void invoke(Request request, Response response)方法具体进行处理
接下来清理并回收request对象和response对象
注:keepAlive表示是否是持久连接
最后是检查输入流是否有未读完的字节并跳过这些字节和关闭socket实例。
下面是一个简单的容器,实现了org.apache.catalina.Container接口,关键代码如下
public class SimpleContainer implements Container {
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "webroot";
public SimpleContainer() {
} public Loader getLoader() {
return null;
}
public void setLoader(Loader loader) {
} public void invoke(Request request, Response response)
throws IOException, ServletException {
String servletName = ( (HttpServletRequest) request).getRequestURI();
servletName = servletName.substring(servletName.lastIndexOf("/") + 1);
URLClassLoader loader = null;
try {
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(WEB_ROOT);
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
}
catch (IOException e) {
System.out.println(e.toString() );
}
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((HttpServletRequest) request, (HttpServletResponse) response);
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
}
}
}
该方法与前面文章的ServletProcessor类的process()方法类似,不再具体分析
---------------------------------------------------------------------------
本系列How Tomcat Works系本人原创
转载请注明出处 博客园 刺猬的温驯
本人邮箱: chenying998179#163.com (#改为@)
本文链接 http://www.cnblogs.com/chenying99/p/3235534.html
How Tomcat Works(六)的更多相关文章
- how tomcat works 六 生命周期
我觉得这一章叫tomcat中的观察者模式,比较好! 首先,不要看本章,请查看一下关于观察者模式的资料比较好. 推荐以下知识点 基础篇 设计模式之禅----观察者模式 大家可以找到pdf阅读一下 另外本 ...
- How Tomcat works — 六、tomcat处理请求
tomcat已经启动完成了,那么是怎么处理请求的呢?怎么到了我们所写的servlet的呢? 目录 Http11ConnectionHandler Http11Processor CoyoteAdapt ...
- How Tomcat Works(十六)
本文接下来会介绍Host容器和Engine容器,在tomcat的实际部署中,总是会使用一个Host容器:本文介绍Host接口和Engine接口及其相关类 Host容器是org.apache.catal ...
- How Tomcat Works(九)
本文接下来描述servlet容器是怎样管理其相关组件的生命周期的,首先本人描述一下事件监听模式,也可以称为观察者模式,该模式分为以下角色 即抽象主题角色 具体主题角色 抽象观察者角色及具体观察者角色, ...
- 攻城狮在路上(肆)How tomcat works(零) 前言说明
最近几篇是关于How tomcat works一书的读书笔记. 通过数个章节逐渐实现一个tomcat的功能. 源码下载地址:http://zhidao.baidu.com/share/7007af0f ...
- How Tomcat works — 四、tomcat启动(3)
上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...
- How Tomcat Works(十四)补充
在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- How Tomcat Works(十七)
在前面的文章中,已经学会了如何通过实例化一个连接器和容器来获得一个servlet容器,并将连接器和容器相关联:但在前面的文章中只有一个连接器可用,该连接器服务8080端口上的HTTP请求,无法添加另一 ...
随机推荐
- 通知(NSNotification)
通知 一个完整的通知一般包含3个属性: - (NSString *)name; // 通知的名称 - (id)object; // 通知发布者(是谁要发布通知) - (NSDictionary *)u ...
- 安装完eclipse,dbwear后,需要在他们解压文件.ini下加上你liux的jdk的安装路径,才能正常使用
-vm/usr/java/jdk/jdk1.6.0_45/bin/java
- C++类构造函数初始化列表
C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class CExample {public: ...
- Android EventBus源码解析
项目地址 :https://github.com/greenrobot/EventBus 这个项目个人感觉就是为了解决回调事件过多的,比方说A函数在做完以后 要调用b类的c函数,那我们通常的做法就是 ...
- win7下折腾filezilla_client
基本上参照 http://blog.csdn.net/iamoyjj/article/details/6358742 但发现这样做的话,engine 生成的 lib中死活都没idn_free 及idn ...
- 嵌入式 详解udev
如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策略.在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev ...
- [Papers]NSE, $u$, Lorentz space [Sohr, JEE, 2001]
$$\bex \bbu\in L^{p,r}(0,T;L^{q,\infty}(\bbR^3)),\quad\frac{2}{p}+\frac{3}{q}=1,\quad 3<q<\inf ...
- file的getPath getAbsolutePath和getCanonicalPath的不同
file的这几个取得path的方法各有不同,下边说说详细的区别 概念上的区别:(内容来自jdk,个人感觉这个描述信息,只能让明白的人明白,不明白的人看起来还是有点难度(特别试中文版,英文版稍好些)所以 ...
- Ajax轮询以及Comet模式—写在Servlet 3.0发布之前(转)
2008 年的夏天,偶然在网上闲逛的时候发现了 Comet 技术,人云亦云间,姑且认为它是由 Dojo 的 Alex Russell 在 2006 年提出.在阅读了大量的资料后,萌发出写篇 blog ...
- sqlserver数据可空插入报错
数据库和C#中均为可空类型. 这时候直接给字段赋值为null parameters[9].Value = null : 执行的时候报错了,一大堆,总之说它少了一个参数. 用sql ser ...