本文接下来介绍tomcat的默认连接器,Tomcat中的默认连接器必须满足以下要求:

  • 实现org.apache.catalina.Connector接口

  • 负责创建实现org.apache.catalina.Request接口的Request对象

  • 负责创建实现org.apache.catalina.Response接口的Response对象

org.apache.catalina.Connector接口最重要的方法是getContainer() 、setContainer()、creatRequest()、 creatResponse(),setContainer()方法用于设置相关联的servlet容器,getContainer()方法获取相关连的servlet容器,creatRequest()方法为http请求创建request对象,creatResponse()方法创建response对象

下面来分析HttpConnector类实现,HttpConnector类同时实现了org.apache.catalina.Connector接口org.apache.catalina.Lifecycle接口(用于生命周期管理)、java.lang.Runnable接口(多线程接口)

在HttpConnector对象的初始化方法initialize()里面,调用私有方法open(),创建ServerSocket实例

private ServerSocket open()
throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException,
KeyManagementException
{ // Acquire the server socket factory for this Connector
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);
}
} // Open a server socket on the specified address
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);
}
} }

上面的ServerSocketFactory factory = getFactory()显然是创建ServerSocket实例的工厂,方法如下

 /**
* Return the server socket factory used by this Container.
*/
public ServerSocketFactory getFactory() { if (this.factory == null) {
synchronized (this) {
this.factory = new DefaultServerSocketFactory();
}
}
return (this.factory); }

工厂类DefaultServerSocketFactory实现了ServerSocketFactory接口

public final class DefaultServerSocketFactory implements ServerSocketFactory {

    public ServerSocket createSocket (int port)
throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException,
KeyManagementException { return (new ServerSocket(port)); } public ServerSocket createSocket (int port, int backlog)
throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException,
KeyManagementException { return (new ServerSocket(port, backlog)); } public ServerSocket createSocket (int port, int backlog,
InetAddress ifAddress)
throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException,
KeyManagementException { return (new ServerSocket(port, backlog, ifAddress)); } }

下面接着分析用于生命周期的start()方法

/**
* Begin processing requests via this Connector.
*
* @exception LifecycleException if a fatal startup error occurs
*/
public void start() throws LifecycleException { // Validate and update our current state
if (started)
throw new LifecycleException
(sm.getString("httpConnector.alreadyStarted"));
threadName = "HttpConnector[" + port + "]";
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true; // Start our background thread
threadStart(); // Create the specified minimum number of processors
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;
HttpProcessor processor = newProcessor();
recycle(processor);
} }

首先是启动HttpConnector连接器线程,然后是初始化最少数量的HttpProcessor处理器入栈

 /**
* Start the background processing thread.
*/
private void threadStart() { log(sm.getString("httpConnector.starting")); thread = new Thread(this, threadName);
thread.setDaemon(true);
thread.start(); }

由于HttpConnector连接器实现了java.lang.Runnable接口,我们分析它的run()方法实现

/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
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 {
// if (debug >= 3)
// log("run: Waiting on serverSocket.accept()");
socket = serverSocket.accept();
// if (debug >= 3)
// log("run: Returned from serverSocket.accept()");
if (connectionTimeout > 0)
socket.setSoTimeout(connectionTimeout);
socket.setTcpNoDelay(tcpNoDelay);
} catch (AccessControlException ace) {
log("socket accept security exception", ace);
continue;
} catch (IOException e) {
// if (debug >= 3)
// log("run: Accept returned IOException", e);
try {
// If reopening fails, exit
synchronized (threadSync) {
if (started && !stopped)
log("accept error: ", e);
if (!stopped) {
// if (debug >= 3)
// log("run: Closing server socket");
serverSocket.close();
// if (debug >= 3)
// log("run: Reopening server socket");
serverSocket = open();
}
}
// if (debug >= 3)
// log("run: IOException processing completed");
} catch (IOException ioe) {
log("socket reopen, io problem: ", ioe);
break;
} catch (KeyStoreException kse) {
log("socket reopen, keystore problem: ", kse);
break;
} catch (NoSuchAlgorithmException nsae) {
log("socket reopen, keystore algorithm problem: ", nsae);
break;
} catch (CertificateException ce) {
log("socket reopen, certificate problem: ", ce);
break;
} catch (UnrecoverableKeyException uke) {
log("socket reopen, unrecoverable key: ", uke);
break;
} catch (KeyManagementException kme) {
log("socket reopen, key management problem: ", kme);
break;
} continue;
} // Hand this socket off to an appropriate processor
HttpProcessor processor = createProcessor();
if (processor == null) {
try {
log(sm.getString("httpConnector.noProcessor"));
socket.close();
} catch (IOException e) {
;
}
continue;
}
// if (debug >= 3)
// log("run: Assigning socket to processor " + processor);
processor.assign(socket); // The processor will recycle itself when it finishes } // Notify the threadStop() method that we have shut ourselves down
// if (debug >= 3)
// log("run: Notifying threadStop() that we have shut down");
synchronized (threadSync) {
threadSync.notifyAll();
} }

上面方法中,监听客户端的http请求,当监听到http请求时,获取Socket实例,然后委派给HttpProcessor对象进行处理(处理器线程吧),最后是如果收到停止连接器线程命令, 则事件通知可以停止线程了

在上面我们还没有来得及分析HttpProcessor对象的初始化相关,所以要重新回到start()方法(源码分析有时要跟踪方法中对多个其他方法的调用,深度优先则顾此失彼,难以兼顾;而广度优先则不便纵向深入)

 // Create the specified minimum number of processors
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;
HttpProcessor processor = newProcessor();
recycle(processor);
}

这里是创建最少数量的HttpProcessor处理器并入栈,我们先分析newProcessor()方法的实现

/**
* Create and return a new processor suitable for processing HTTP
* requests and returning the corresponding responses.
*/
private HttpProcessor newProcessor() { // if (debug >= 2)
// log("newProcessor: Creating new processor");
HttpProcessor processor = new HttpProcessor(this, curProcessors++);
if (processor instanceof Lifecycle) {
try {
((Lifecycle) processor).start();
} catch (LifecycleException e) {
log("newProcessor", e);
return (null);
}
}
created.addElement(processor);
return (processor); }

我们可以看到,这里主要是实例化HttpProcessor对象,传入HttpConnector实例本身(里面要用到HttpConnector对象的创建Request对象方法和创建Response对象方法),然后向上转型为Lifecycle接口类型,并调用它的start()方法,接着Vector created = new Vector()成员变量添加该HttpProcessor对象(Vector实现List接口,内部采用数组实现,其操作方法支持线程同步),最后返回实例

/**
* Recycle the specified Processor so that it can be used again.
*
* @param processor The processor to be recycled
*/
void recycle(HttpProcessor processor) { // if (debug >= 2)
// log("recycle: Recycling processor " + processor);
processors.push(processor); }

这里将HttpProcessor对象入栈,成员变量Stack processors = new Stack()继承自Vector,是一种先进后出的数据结构

我们现在来分析run()方法里面的相关源码,也许更容易理解

/**
* Create (or allocate) and return an available processor for use in
* processing a specific HTTP request, if possible. If the maximum
* allowed processors have already been created and are in use, return
* <code>null</code> instead.
*/
private HttpProcessor createProcessor() { synchronized (processors) {
if (processors.size() > 0) {
// if (debug >= 2)
// log("createProcessor: Reusing existing processor");
return ((HttpProcessor) processors.pop());
}
if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
// if (debug >= 2)
// log("createProcessor: Creating new processor");
return (newProcessor());
} else {
if (maxProcessors < 0) {
// if (debug >= 2)
// log("createProcessor: Creating new processor");
return (newProcessor());
} else {
// if (debug >= 2)
// log("createProcessor: Cannot create new processor");
return (null);
}
}
} }

这里是从Stack processors = new Stack()成员变量里面获取HttpProcessor对象 ,后面的代码不用多加解释了吧,你懂的!

后面那段代码是干嘛的

// Notify the threadStop() method that we have shut ourselves down
// if (debug >= 3)
// log("run: Notifying threadStop() that we have shut down");
synchronized (threadSync) {
threadSync.notifyAll();
}

我们看到threadStop()方法里面的代码,可以看出上面的代码块是用来通知线程停止的

/**
* Stop the background processing thread.
*/
private void threadStop() { log(sm.getString("httpConnector.stopping")); stopped = true;
try {
threadSync.wait(5000);
} catch (InterruptedException e) {
;
}
thread = null; }

由于HttpProcessor处理器类的源码分析相对独立,加上篇幅还比较多,因此本文先到这里,下文继续……

---------------------------------------------------------------------------

本系列How Tomcat Works系本人原创

转载请注明出处 博客园 刺猬的温驯

本人邮箱: chenying998179#163.com (#改为@)

本文链接 http://www.cnblogs.com/chenying99/p/3235530.html

How Tomcat Works(五)的更多相关文章

  1. How Tomcat works — 五、tomcat启动(4)

    前面摆了三节的姿势,现在终于要看到最终tomcat监听端口,接收请求了. 目录 Connector Http11Protocol JIoEndpoint 总结 在前面的初始化都完成之后,进行Conne ...

  2. how tomcat works 五 servlet容器 上

    servlet容器是用来处理请求servlet资源,并为Web客户端填充response对象的模块.在上一篇文章(也就是书的第四章)我们设计了SimpleContainer类,让他实现Containe ...

  3. How Tomcat Works(十五)

    本文接下来分析Context容器,Context容器实例表示一个具体的Web应用程序,其中包括一个或多个Wrapper实例:不过Context容器还需要其他的组件支持,典型的如载入器和Session管 ...

  4. How Tomcat Works(十)

    本文接下来分析tomcat的日志记录器,日志记录器是用来记录消息的组件,在tomcat中,日志记录器需要与某个servlet容器相关连:在org.apache.catalina.logger包下,to ...

  5. how tomcat works 札记(两)----------一个简单的servlet集装箱

    app1 (看着眼前这章建议读者,看how tomcat works 札记(一个)----------一个简单的webserver http://blog.csdn.net/dlf123321/art ...

  6. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  7. 攻城狮在路上(肆)How tomcat works(零) 前言说明

    最近几篇是关于How tomcat works一书的读书笔记. 通过数个章节逐渐实现一个tomcat的功能. 源码下载地址:http://zhidao.baidu.com/share/7007af0f ...

  8. How Tomcat works — 四、tomcat启动(3)

    上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...

  9. How Tomcat Works(十四)补充

    在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...

随机推荐

  1. [Web前端系列之_Firebug_00_序]

    [因] 以前一直把Firebug当做参考他人网站界面结构的工具,看看css,js等,没有深挖.这段时间在项目组里主要充当前台工作,也有空,就准备把前端给精通点,firebug作为入手点. [参考资料] ...

  2. linux shared lib 使用与编译

    一.              动态链接库的原理及使用 Linux提供4个库函数.一个头文件dlfcn.h以及两个共享库(静态库libdl.a和动态库libdl.so)支持动态链接. Ø        ...

  3. IOS中(类似于进度条哪种效果)MBProgressHUD的使用

    1.显示HUD MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; hud.labelText = ...

  4. OK335xS Linux kernel check clock 24M hacking

    /****************************************************************************** * OK335xS Linux kern ...

  5. 中小型数据库 RMAN CATALOG 备份恢复方案(一)

    对于数据库的稳定性,高可用,跨平台以及海量数据库的处理,Oracle 数据库通常是大型数据库和大企业的首选.尽管如此,仍然不乏很多中小企业想要品尝一下Oracle腥味,因此在Oracle环境中也有不少 ...

  6. eclipse环境下tomcat远程调试方法

    前提:Windows环境tomcat是以catalina.bat方式而非Windows服务形式启动(两者所使用的JAVA配置及JVM参数会有差异). 服务器段设置 方法1:修改CATALINA_OPT ...

  7. 【转】Github轻松上手2-如何使用命令行创建和管理repo

    转自:http://blog.sina.com.cn/s/blog_4b55f6860100zzhd.html 如果你对这种怀旧的方式很感冒,不妨参考这里: http://help.github.co ...

  8. [Everyday Mathematics]20150218

    设 $A,B$ 是 $n$ 阶复方阵, 适合 $$\bex A^2B+BA^2=2ABA. \eex$$ 试证: 存在 $k\in\bbZ^+$, 使得 $(AB-BA)^k=0$.

  9. backbone-1.3.3源码解析-----------Event

    第一次写,写的不对的请指正 backbone.js中的Event实现了自定义事件.自定义事件就是一个对象的键值对,key为事件名,value为一个function数组.在backbone这个对象中有一 ...

  10. java Comparable 比较器的使用

    /** * */ package com.mindreader; import java.util.Arrays; /** * @作者 Mind reader * @内容 对象数组排序——Compar ...