上文说了简单的servlet解析过程。实际上,tomcat在解析servlet的 时候是吧连接器定位为满足以下三个条件:
1、必须事先接口org.apache.catalina.Connector
2. 必须创建请求对象,该请求对象的类必须实现接口org.apache.catalina.Request。
3. 必须创建响应对象,该响应对象的类必须实现接口org.apache.catalina.Response。
tomcat的连接器有很多种类:Coyote、mode_jk、mod_jk2和mode_webapp等。
来自浏览器的请求类型是有区别的http/0.9 http/1.0 http/1.1.
http/1.1又叫做持久连接,上文中一次请求处理完毕就关闭了socket。然而,在现实的页面请求中需要加载多种资源(js、img css)。如果每次请求都开启关闭连接那将是非常耗时的事情。http/1.1能够让浏览器和服务器保持一种持久化的连接,快速的相应请求。这样,请求的形式就和之前不同,他是一块编码的形式,并使用特殊头部transfer-encoding感知发送过来的数据信息。同时,如果浏览器有较大数据请求之前发送头部信息Expect: 100-continue头部到服务器,等待服务器的相应。如果服务器响应数据能够接受大数据请求,才真正的发送数据,避免先发送大数据而遭服务器拒绝而浪费了传输数据的带宽资源。
本文重点说明连接器的演进。
连接器的演进主要包括了以下几个方面:
1、处理请求不再只是一次处理一次请求,而是生成Processor池,用于处理多个连接请求。同事Processor处理器也不再是每次请求新生成实例处理请求,而是从池子中获取到一个处理器去完成请求。同时,实现了Processor处理方法异步化,让连接器线程能够继续接受其他的请求。
2、处理器线程和连接器线程通过wait() notifyAll()的方式进行线程间通信。
3、Processor处理器中,增加了标识符,KeepAlive、stopped和http11,为处理器在处理的过程中设定“路口”,及时相应请求的变化。
4、socket缓冲区大小不再是像前文一样设置为定值,而是通过获取连接器传递过来的参数设置缓冲区大小。
5、处理器的职能更加的丰富。
连接处理 parseConnection,针对不同的连接协议做不同的处理。
解析请求 parseRequest
解析头部 parseHeaders
6、去掉了静态处理器,暂时无法接受静态资源请求。
------------------------
1、连接器启动:
HttpConnector connector = new HttpConnector();
SimpleContainer container = new SimpleContainer();
connector.setContainer(container);
try {
//初始化连接器,打开socket连接
connector.initialize();
//开启监听,开启连接器线程、将处理器线程启动并入队列。
connector.start();
System.in.read();
}
catch (Exception e) {
e.printStackTrace();
}
1.1 初始化连接、打开socket连接(使用工厂模式)
public void initialize()
throws LifecycleException {
//初始化标志,不能重复初始化
if (initialized)
throw new LifecycleException (
sm.getString("httpConnector.alreadyInitialized"));
this.initialized=true;
Exception eRethrow = null;
// Establish a server socket on the specified port
try {
//打开socket连接
serverSocket = open();
} catch (IOException ioe) {
log("httpConnector, io problem: ", ioe);
eRethrow = ioe;
} catch (KeyStoreException kse) {
log("httpConnector, keystore problem: ", kse);
eRethrow = kse;
} catch (NoSuchAlgorithmException nsae) {
log("httpConnector, keystore algorithm problem: ", nsae);
eRethrow = nsae;
} catch (CertificateException ce) {
log("httpConnector, certificate problem: ", ce);
eRethrow = ce;
} catch (UnrecoverableKeyException uke) {
log("httpConnector, unrecoverable key: ", uke);
eRethrow = uke;
} catch (KeyManagementException kme) {
log("httpConnector, key management problem: ", kme);
eRethrow = kme;
}
if ( eRethrow != null )
throw new LifecycleException(threadName + ".open", eRethrow);
}
private ServerSocket open()
throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException,
KeyManagementException
{
// Acquire the server socket factory for this Connector
//获得服务器socket工厂实例
ServerSocketFactory factory = getFactory();
// If no address is specified, open a connection on all addresses
//如果没有指定地址,在所有地址上打开一个连接
if (address == null) {
log(sm.getString("httpConnector.allAddresses"));
try {
return (factory.createSocket(port, acceptCount));
} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + port);
}
}
//在指定地址上打开一个连接
try {
InetAddress is = InetAddress.getByName(address);
log(sm.getString("httpConnector.anAddress", address));
try {
return (factory.createSocket(port, acceptCount, is));
} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + address +
":" + port);
}
} catch (Exception e) {
log(sm.getString("httpConnector.noAddress", address));
try {
return (factory.createSocket(port, acceptCount));
} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + port);
}
}
}
1.2、开启监听,开启连接器线程、将处理器线程启动并入队列。
//为连接器绑定指定数量的处理器
public void start() throws LifecycleException {
//判断该线程的connect开启状态,避免重复开启
if (started)
throw new LifecycleException
(sm.getString("httpConnector.alreadyStarted"));
threadName = "HttpConnector[" + port + "]";
//打开监听
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our background thread
//开启一个后台连接器线程
threadStart();
//创建处理器,并调用recyle方法将其放置到栈队列中
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;
HttpProcessor processor = newProcessor();
recycle(processor);
}
}
2、连接器、容器之间的协作关系
2.1 容器派发socket到处理器线程
public void run() {
// Loop until we receive a shutdown command
//开启循环,知道我们获得了结束命令
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {
//获得socket请求
socket = serverSocket.accept();
// 设置超时时间
if (connectionTimeout > 0)
socket.setSoTimeout(connectionTimeout);
//设置tcp nodelay属性
socket.setTcpNoDelay(tcpNoDelay);
} catch (AccessControlException ace) {
//抛出连接安全错误信息
log("socket accept security exception", ace);
continue;
} catch (IOException e) {
try {
// If reopening fails, exit
//如果再次开启失败,退出
synchronized (threadSync) {
if (started && !stopped)
log("accept error: ", e);
if (!stopped) {
// 关闭异常连接
serverSocket.close();
// 重新开启异常连接
serverSocket = open();
}
}
// 异常处理,包括不限于秘钥等错误请求
} catch (Exception ioe) {
log("socket reopen, io problem: ", ioe);
break;
}
continue;
}
//判断处理器栈是否有可用处理器,没有按规则生成,有则获取栈中处理器
HttpProcessor processor = createProcessor();
//获取处理器为空,可能情况是请求数量过多,超过了承受的最大处理器个数
if (processor == null) {
try {
log(sm.getString("httpConnector.noProcessor"));
socket.close();
} catch (IOException e) {
;
}
continue;
}
//派发socket到处理器
processor.assign(socket);
// The processor will recycle itself when it finishes
}
//获取到了结束命令,通知其他线程
synchronized (threadSync) {
threadSync.notifyAll();
}
}
2.2处理器接收到派发socket
synchronized void assign(Socket socket) {
// d等待该处理器的其它socket处理执行完毕
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
//将新获取的socket放置到处理器中,并发送线程通知
this.socket = socket;
available = true;
notifyAll();
if ((debug >= 1) && (socket != null))
log(" An incoming request is being assigned");
}
2.3 处理器接收到了socket请求,准备处理
public void run() {
// Process requests until we receive a shutdown signal
while (!stopped) {
// Wait for the next socket to be assigned
//等待连接器的socket请求
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
try {
//处理socket请求
process(socket);
} catch (Throwable t) {
log("process.invoke", t);
}
// Finish up this request
//处理完毕,将该processor线程归还给Stack processors 用来处理接下来的socket请求
connector.recycle(this);
}
// Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
//该处理器线程退出,通知其他processor
threadSync.notifyAll();
}
}
未完待续