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)为各种容器建立映射关系

时间: 2024-10-13 06:37:04

Tomcat Connector的相关文章

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

Tomcat Connector的三种不同的运行模式性能相差很大,有人测试过的结果如下: 这三种模式的不同之处如下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomcat7或以下,在Linux系统中默认使用这种方式. NIO: 利用Java的异步IO处理,可以通过少量的线程处理大量的请求. Tomcat8在Linux系统中默认使用这种方式. Tomcat7必须修改Connector配置来启动: <Connector port="8080" pro

tomcat connector连接器

Connector是Tomcat最核心的组件之一,负责处理一个WebServer最核心的连接管理.Net IO.线程(可选).协议解析和处理的工作.一.连接器介绍在开始Connector探索之路之前,先看看Connector几个关键字 NIO:Tomcat可以利用Java比较新的NIO技术,提升高并发下的Socket性能 AJP:Apache JServ Protocol,AJP的提出当然还是为了解决java亘古不变的问题——性能,AJP协议是基于包的长连接协议,以减少前端Proxy与Tomca

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

Tomcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一.不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio.nio.apr三种运行模式,那么这三种运行模式有什么区别呢,我们又如何修改Tomcat Connector的运行模式来提高Tomcat的运行性能呢? 下面,我们先大致了解Tomcat Connector的三种运行模式. bio bio(blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传

Tomcat Connector的三种运行模式

详情参考: http://tomcat.apache.org/tomcat-7.0-doc/apr.html http://www.365mini.com/page/tomcat-connector-mode.htm 操作环境:rhel6.3 x86_x64. tomcat7.0.42 tomcat connector三种运行模式分别为:bio.nio和apr.你可以简单地理解成,性能上:bio<nio<=apr 其中bio为默认运行方式,即(server.xml): <Connecto

The Apache Tomcat Connector

http://tomcat.apache.org/connectors-doc/generic_howto/quick.html 搭建最简单的tomcat connector 用到了apapche 的mod_jk 模块 . 下载编译 tomcat connector wget http://mirrors.cnnic.cn/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.40-src.tar.gz tar xzf tomcat-c

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

Tomcat Connector的三种不同的执行模式性能相差非常大,有人測试过的结果例如以下: 这三种模式的不同之处例如以下: BIO: 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomcat7或下面,在Linux系统中默认使用这样的方式. NIO: 利用Java的异步IO处理.能够通过少量的线程处理大量的请求. Tomcat8在Linux系统中默认使用这样的方式. Tomcat7必须改动Connector配置来启动: <Connector port="8080&qu

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 use or the connector may be misconfigured.错误 一开始,我以为是端口占用,baidu   https://blog.csdn.net/IBLiplus/article/details/82714151,用这个办法,还是没有解决问题,看上去不是端口占用问题,

tomcat connector : bio nio apr

先记录 BIO: blocking I/O,阻塞式I/O操作 一个线程处理一个请求.缺点:并发量高时,线程数较多,浪费资源. Tomcat7或以下,在Linux系统中默认使用这种方式. NIO:non-blocking I/O 利用Java的异步IO处理,可以通过少量的线程处理大量的请求. Tomcat8在Linux系统中默认使用这种方式. Tomcat7必须修改Connector配置来启动: <Connector port="8080" protocol="org.a

Tomcat Connector(BIO, NIO, APR)三种运行模式(转)

Tomcat支持三种接收请求的处理方式:BIO.NIO.APR . BIO 阻塞式I/O操作即使用的是传统 I/O操作,Tomcat7以下版本默认情况下是以BIO模式运行的,由于每个请求都要创建一个线程来处理,线程开销较大,不能处理高并发的场景,在三种模式中性能也最低. 配置如下(tomcat安装目录下的/conf/server.xml): <Connector port="8080" protocol="HTTP/1.1" connectionTimeout