转自: 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的更多相关文章

  1. Tomcat Connector三种运行模式(BIO, NIO, APR)的比较和优化

    Tomcat Connector的三种不同的运行模式性能相差很大,有人测试过的结果如下: 这三种模式的不同之处如下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomc ...

  2. 修改Tomcat Connector运行模式,优化Tomcat运行性能

    Tomcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一.不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运 ...

  3. Tomcat Connector的三种运行模式

    详情参考: http://tomcat.apache.org/tomcat-7.0-doc/apr.html http://www.365mini.com/page/tomcat-connector- ...

  4. 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 ...

  5. 修改 Tomcat Connector运行模式 优化Tomcat运行性能

    omcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一.不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运行 ...

  6. Tomcat Connector三种执行模式(BIO, NIO, APR)的比較和优化

    Tomcat Connector的三种不同的执行模式性能相差非常大,有人測试过的结果例如以下: 这三种模式的不同之处例如以下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. ...

  7. Tomcat Connector的三种不同的运行模式

    Tomcat Connector的三种不同的运行模式性能相差很大,有人测试过的结果如下: 这三种模式的不同之处如下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomc ...

  8. 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 ...

  9. 【Tomcat】Tomcat Connector的三种运行模式【bio、nio、apr】

    Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运行模式 bio bio(blocking I/O,阻塞式I/O操作),表示Tomcat使用的是传统的Java I/O ...

  10. The Apache Tomcat Connector

    http://tomcat.apache.org/connectors-doc/generic_howto/quick.html 搭建最简单的tomcat connector 用到了apapche 的 ...

随机推荐

  1. Jsoup爬虫解析

    需要下载jsoup-1.8.1.jar包 jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQue ...

  2. 如何使用Soft-NMS实现目标检测并提升准确率

    非极大值抑制(Non-Maximum suppression,NMS)是物体检测流程中重要的组成部分.它首先基于物体检测分数产生检测框,分数高的检测框M被选中,其他与被选中检测框又明显重叠的检测框被抑 ...

  3. 【剑指offer】用两个栈实现队列

    一.题目: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 二.思路: 两个栈A,B,A负责进栈,B负责出栈,进栈很容易,A中添加即可,出栈需要从B里出,所以要先 ...

  4. PHP解决搜索时在URL地址栏输入中文字符搜索结果出现乱码

    这 个问题的出现的前提是本站代码采用utf-8格式,php空间当页面停留在搜索页面时,在浏览器的地址栏输入中文的关键字进行搜索时会出现乱码,在网上查找资料说 明,是因为浏览器默认将url中的中文字符编 ...

  5. AngularJS2.0起步

    ES6工具链 要让Angular2应用跑起来不是件轻松的事,因为它用了太多还不被当前主流浏览器支持的技术.所以,我们需要一个工具链:

  6. Logistic Regression Using Gradient Descent -- Binary Classification 代码实现

    1. 原理 Cost function Theta 2. Python # -*- coding:utf8 -*- import numpy as np import matplotlib.pyplo ...

  7. 2018-2019-2 网络对抗技术 20165324 Exp5:MSF基础应用

    2018-2019-2 网络对抗技术 20165324 Exp5:MSF基础应用 MSF基础知识: MSF基础框架: 主要模块模块(Module).模块是指Metasploit框架中所使用的一段软件代 ...

  8. POJ 3461 Oulipo(KMP,模式串在主串中出现次数 可重叠)

    题意:给你两个字符串p和s,求出p在s中出现的次数. 显然,我们要先把模式串放到前面,之后主串放后面,中间隔开,这样就可以根据前缀数组的性质来求了. 我先想直接把p接到s前面,之后求Next数组对st ...

  9. js之数组排序

    数组,大家都不陌生,只要是学编程的人都知道这个入门的数据结构,在js中也是有数组这个概念的,跟普通的数组一样只是定义的形式不同罢了.下面是一个数组的排序代码: <html> <hea ...

  10. csv到mysql数据库如何分割

          这两天修改一个取XML文件存入到CSV,然后再存入到mysql的bug,bug是XML文件里面有个name字段,存入CSV文件里面的时候我们用“|”,来分割字段.但是name里面有时候也有 ...