Tomcat Connector
转自: http://blog.csdn.net/aesop_wubo/article/details/7617416
如下图所示,Tomcat服务器主要有两大核心模块组成:连接器和容器,本节只分析连接器的实现。
连接器主要是接收用户的请求,然后封装请求传递给容器处理,tomcat中默认的连接器是Coyote.首先来看连接器的类图:

protocol
我们发现这个类里面有很多与protocol有关的属性和方法,tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3,查看tomcat的配置文件server.xml可以看到如下配置:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="utf-8"/> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
HTTP/1.1协议负责建立HTTP连接,web应用通过浏览器访问tomcat服务器用的就是这个连接器,默认监听的是8080端口;
AJP/1.3协议负责和其他HTTP服务器建立连接,监听的是8009端口,比如tomcat和apache或者iis集成时需要用到这个连接器。
协议上有三种不同的实现方式:JIO、APR、NIO。
JIO(java.io):用java.io纯JAVA编写的TCP模块,这是tomcat默认连接器实现方法;
APR(Apache Portable Runtime):有C语言和JAVA两种语言实现,连接Apache httpd Web服务器的类库是在C中实现的,同时用APR进行网络通信;
NIO(java.nio):这是用纯Java编写的连接器(Conector)的一种可选方法。该实现用java.nio核心Java网络类以提供非阻塞的TCP包特性。
ProtocolHandler接口是对这些协议的抽象,其类层次结构图如下呼所示:

前面提到tomcat默认采用的是Http11Protocol,要么要怎么更换默认的protocolHandler呢,先看看setProtocol方法的源码:
public void setProtocol(String protocol) {
if (AprLifecycleListener.isAprAvailable()) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpAprProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
} else {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
}
} else {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11Protocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
}
从以上代码可以看出只要protocol不为HTTP/1.1也不为AJP/1.3就会调用setProtocolHandlerClassName来设置protocolHandler,也就是说要替换默认的protocolHandler,只需要修改server.xml文件Connector中的protocol属性即可!
Service
连接器和容器一起才能对外提供服务,Service里面包含了一个容器和多个连接器,连接器是怎么加入到Service中的,可以看一下StandardService中的代码:
public void addConnector(Connector connector) {
synchronized (connectors) {
connector.setService(this);
Connector results[] = new Connector[connectors.length + 1];
System.arraycopy(connectors, 0, results, 0, connectors.length);
results[connectors.length] = connector;
connectors = results;
if (getState().isAvailable()) {
try {
connector.start();
} catch (LifecycleException e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
// Report this property change to interested listeners
support.firePropertyChange("connector", null, connector);
}
}
StandardService中还有setContainer方法,正是Service把容器和连接器关联在一起的
mapperListener
在连接器初始化的时候会初始化mapperListener,mapperListener在初始化的时候会调用mapper对象的addXXX方法

Mapper对象在tomcat中存在于两个地方:
1、每个context容器对象中,它只记录了此context内部的访问资源与相对应的wrapper子容器的映射;
2、connector模块中,这是tomcat全局的变量,它记录了一个完整的映射对应关系,即根据访问的完整URL如何定位到哪个host下的哪个context的哪个wrapper容器。
Servlet中forward跳转会用到第一种mapper,也就是说forward是服务器内部的重定向。
初始化与启动
Connector的初始化过程如下:
1、Tomcat初始化时会调用Bootstrap的Load方法,这里会解析XML文件,Digester解析的过程中,会调用Connector的构造方法
public Connector(String protocol) {
setProtocol(protocol);
// Instantiate protocol handler
try {
Class<?> clazz = Class.forName(protocolHandlerClassName);
this.protocolHandler = (ProtocolHandler) clazz.newInstance();
} catch (Exception e) {
log.error(sm.getString(
"coyoteConnector.protocolHandlerInstantiationFailed"), e);
}
}
这个构造方法首先设置protocol,然后初始化protocolhandler
2、紧接着初始化Server,一个Server可能有多个Service,在初始化Server的过程中会初始化多个Service.Service由一个容器和多个连接器组成,会先初始化容器,然后初始化化两个连接器,连接器的初始化是调用的Connector的initInternal方法
protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
// Make sure parseBodyMethodsSet has a default
if( null == parseBodyMethodsSet ) {
setParseBodyMethods(getParseBodyMethods());
}
try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
// Initialize mapper listener
mapperListener.init();
}
(1)首先为protocolHandler设置一个adapter,然后初始化protocolHandler
(2)初始化mapperListener,啥都没做,只是调用了父类(LifecycleMBeanBase)的initInternal方法!
由于Tomcat的生命周期控制,连接器的启动过程和初始化过程几乎一样,也是由Catalina的start方法开始,Server启动,Service启动,Container启动,Connector启动。Connector启动调用了它的startInternal方法,这个方法只做了两件事:启动protocolHandler和mapperListener,连接器的启动过程就是这样!下面分别来看看protocolHandler和mapperListener启动时都做了哪些事?
protocolHandler的初始化是在其父类AbstractProtocol的start方法中完成的,
public void start() throws Exception {
if (getLog().isInfoEnabled())
getLog().info(sm.getString("abstractProtocolHandler.start",
getName()));
try {
endpoint.start();
} catch (Exception ex) {
getLog().error(sm.getString("abstractProtocolHandler.startError",
getName()), ex);
throw ex;
}
}
调用了endpoint的start方法,这个方法里面做了以下几件事:
(1)设置接收线程数和最大连接数,创建socket
(2)创建线程池,启动监听的线程监听用户请求
(3)启动一个线程来负责异步请求
mapperListener也继承了LifecycleMBeanBase类,也是受生命周期控制的。所以它的启动是在startInternal方法中完成的
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
// Find any components that have already been initialized since the
// MBean listener won't be notified as those components will have
// already registered their MBeans
findDefaultHost();
Engine engine = (Engine) connector.getService().getContainer();
addListeners(engine);
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
// Registering the host will register the context and wrappers
registerHost(host);
}
}
}
(1)注册已初始化的组件
(2)为各种容器添加监听器
(3)为各种容器建立映射关系
Tomcat Connector的更多相关文章
- Tomcat Connector三种运行模式(BIO, NIO, APR)的比较和优化
Tomcat Connector的三种不同的运行模式性能相差很大,有人测试过的结果如下: 这三种模式的不同之处如下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomc ...
- 修改Tomcat Connector运行模式,优化Tomcat运行性能
Tomcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一.不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运 ...
- Tomcat Connector的三种运行模式
详情参考: http://tomcat.apache.org/tomcat-7.0-doc/apr.html http://www.365mini.com/page/tomcat-connector- ...
- The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured
springboot 8080端口被占用报错:The Tomcat connector configured to listen on port 8080 failed to start. The p ...
- 修改 Tomcat Connector运行模式 优化Tomcat运行性能
omcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一.不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运行 ...
- Tomcat Connector三种执行模式(BIO, NIO, APR)的比較和优化
Tomcat Connector的三种不同的执行模式性能相差非常大,有人測试过的结果例如以下: 这三种模式的不同之处例如以下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. ...
- Tomcat Connector的三种不同的运行模式
Tomcat Connector的三种不同的运行模式性能相差很大,有人测试过的结果如下: 这三种模式的不同之处如下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomc ...
- springboot Tomcat connector configured to listen on port 8081 failed to start.
启动报 Tomcat connector configured to listen on port 8081 failed to start. The port may already be in ...
- 【Tomcat】Tomcat Connector的三种运行模式【bio、nio、apr】
Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运行模式 bio bio(blocking I/O,阻塞式I/O操作),表示Tomcat使用的是传统的Java I/O ...
- The Apache Tomcat Connector
http://tomcat.apache.org/connectors-doc/generic_howto/quick.html 搭建最简单的tomcat connector 用到了apapche 的 ...
随机推荐
- lua源代码学习(一)lua的c api外围实现
工作后,整个人已经比較松懈了.尽管一直在看lua的源代码.可是一直是比較零碎的时间,没有系统的整理,所以还是收获不多.由于近期工作也不是非常忙了,就想整理下lua的源代码学习的笔记.加深下印象,并分享 ...
- RN例子,发送http请求,日期选择
发送http请求 let map = { method: 'post', headers: { token: '', 'Content-Type': 'application/json' }, bod ...
- mui笔记
1.关闭当前页面执行上一个页面的方法 var preview = plus.webview.currentWebview().opener() //获取当前窗口的创建者,即A preview.eval ...
- GNU
1983年,理查德.斯托曼提出GNU计划(革奴计划),希望发展出一套完整的开放源代码操作系统来取代Unix,计划中的操作系统,名为GNU. 1989年,发表GNU通用公共许可协议(GPL).GPL条款 ...
- 教你玩转产品管理系统iClap(PC端功能篇)
之前和大家介绍了iClap的基础功能, 这一次针对PC端右侧的工具栏再做一个详细的介绍 随着版本的更新迭代,陆续会有更多工具和功能推出! 导航 为项目成员提供网址浏览访问导航服务,帮助项目成员快速查找 ...
- lnmp之php5.6.29安装
linux下lnmp环境之php安装 为了防止出现缺失,安装下面集成,复制的时候请将这个复制成一个整行,下面3行是一整行 [root@localhost src]# yum -y install gc ...
- zoj3814
这题说的是给了一个数在longlong范围内 然后求出小于这个数的最大的回文,枚举每位减去1后 , 他后面的位置上全部都置为9,然后在枚举每个前半部分,然后贪心取得这个数的最大值,贪心的时候写错了,错 ...
- 使用IDEA 搭建SpringMVC +Easyui 实现最简单的数据展示功能
效果图如下: 步骤如下: 1.导入jquery-easyui-1.5.5.6 2.导入相关的SpringMVC 的jar 包 3.编写datagrid.jsp 页面 <%-- Created b ...
- JMeter4.0二次开发之导入eclipse
1.先建立工程,命名为JMeter4.0. JDK版本为10.0.1 2.在官网下载src文件,通过文件系统导入到JMeter4.0工程中 3.在ant中选择download_jars,ant会自动下 ...
- linux常用命令:killall 命令
killall命令用进程的名字来杀死进程. 1.命令格式: killall [ -egiqvw ] [ -signal ] [进程名称] 格式:killall -<signame> ...