文档章节

Tomcat学习之Connector

wangxuwei
 wangxuwei
发布于 2016/09/26 23:15
字数 1492
阅读 21
收藏 0

目录(?)[-]

  1. protocol
  2. Service
  3. mapperListener
  4. 初始化与启动

如下图所示,Tomcat服务器主要有两大核心模块组成:连接器和容器,本节只分析连接器的实现。

连接器主要是接收用户的请求,然后封装请求传递给容器处理,tomcat中默认的连接器是Coyote.首先来看连接器的类图:

protocol

我们发现这个类里面有很多与protocol有关的属性和方法,tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3,查看tomcat的配置文件server.xml可以看到如下配置:

[java] view plain copy

 print?

  1. <Connector port="8080" protocol="HTTP/1.1"   
  2.                connectionTimeout="20000"   
  3.                redirectPort="8443" URIEncoding="utf-8"/>  
  4.   
  5. <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方法的源码:

[java] view plain copy

 print?

  1. public void setProtocol(String protocol) {  
  2.   
  3.     if (AprLifecycleListener.isAprAvailable()) {  
  4.         if ("HTTP/1.1".equals(protocol)) {  
  5.             setProtocolHandlerClassName  
  6.                 ("org.apache.coyote.http11.Http11AprProtocol");  
  7.         } else if ("AJP/1.3".equals(protocol)) {  
  8.             setProtocolHandlerClassName  
  9.                 ("org.apache.coyote.ajp.AjpAprProtocol");  
  10.         } else if (protocol != null) {  
  11.             setProtocolHandlerClassName(protocol);  
  12.         } else {  
  13.             setProtocolHandlerClassName  
  14.                 ("org.apache.coyote.http11.Http11AprProtocol");  
  15.         }  
  16.     } else {  
  17.         if ("HTTP/1.1".equals(protocol)) {  
  18.             setProtocolHandlerClassName  
  19.                 ("org.apache.coyote.http11.Http11Protocol");  
  20.         } else if ("AJP/1.3".equals(protocol)) {  
  21.             setProtocolHandlerClassName  
  22.                 ("org.apache.coyote.ajp.AjpProtocol");  
  23.         } else if (protocol != null) {  
  24.             setProtocolHandlerClassName(protocol);  
  25.         }  
  26.     }  
  27. }  

从以上代码可以看出只要protocol不为HTTP/1.1也不为AJP/1.3就会调用setProtocolHandlerClassName来设置protocolHandler,也就是说要替换默认的protocolHandler,只需要修改server.xml文件Connector中的protocol属性即可!

 

 

Service

连接器和容器一起才能对外提供服务,Service里面包含了一个容器和多个连接器,连接器是怎么加入到Service中的,可以看一下StandardService中的代码:

[html] view plain copy

 print?

  1. public void addConnector(Connector connector) {  
  2.   
  3.     synchronized (connectors) {  
  4.         connector.setService(this);  
  5.         Connector results[] = new Connector[connectors.length + 1];  
  6.         System.arraycopy(connectors, 0, results, 0, connectors.length);  
  7.         results[connectors.length] = connector;  
  8.         connectors = results;  
  9.   
  10.         if (getState().isAvailable()) {  
  11.             try {  
  12.                 connector.start();  
  13.             } catch (LifecycleException e) {  
  14.                 log.error(sm.getString(  
  15.                         "standardService.connector.startFailed",  
  16.                         connector), e);  
  17.             }  
  18.         }  
  19.   
  20.         // Report this property change to interested listeners  
  21.         support.firePropertyChange("connector", null, connector);  
  22.     }  
  23.   
  24. }  

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的构造方法

[html] view plain copy

 print?

  1. public Connector(String protocol) {  
  2.        setProtocol(protocol);  
  3.        // Instantiate protocol handler  
  4.        try {  
  5.            Class<?> clazz = Class.forName(protocolHandlerClassName);  
  6.            this.protocolHandler = (ProtocolHandler) clazz.newInstance();  
  7.        } catch (Exception e) {  
  8.            log.error(sm.getString(  
  9.                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);  
  10.        }  
  11.    }  

这个构造方法首先设置protocol,然后初始化protocolhandler

2、紧接着初始化Server,一个Server可能有多个Service,在初始化Server的过程中会初始化多个Service.Service由一个容器和多个连接器组成,会先初始化容器,然后初始化化两个连接器,连接器的初始化是调用的Connector的initInternal方法

[html] view plain copy

 print?

  1. protected void initInternal() throws LifecycleException {  
  2.   
  3.     super.initInternal();  
  4.   
  5.     // Initialize adapter  
  6.     adapter = new CoyoteAdapter(this);  
  7.     protocolHandler.setAdapter(adapter);  
  8.   
  9.     // Make sure parseBodyMethodsSet has a default  
  10.     if( null == parseBodyMethodsSet ) {  
  11.         setParseBodyMethods(getParseBodyMethods());  
  12.     }  
  13.   
  14.     try {  
  15.         protocolHandler.init();  
  16.     } catch (Exception e) {  
  17.         throw new LifecycleException  
  18.             (sm.getString  
  19.              ("coyoteConnector.protocolHandlerInitializationFailed"), e);  
  20.     }  
  21.   
  22.     // Initialize mapper listener  
  23.     mapperListener.init();  
  24. }  

(1)首先为protocolHandler设置一个adapter,然后初始化protocolHandler

(2)初始化mapperListener,啥都没做,只是调用了父类(LifecycleMBeanBase)的initInternal方法!
由于Tomcat的生命周期控制,连接器的启动过程和初始化过程几乎一样,也是由Catalina的start方法开始,Server启动,Service启动,Container启动,Connector启动。Connector启动调用了它的startInternal方法,这个方法只做了两件事:启动protocolHandler和mapperListener,连接器的启动过程就是这样!下面分别来看看protocolHandler和mapperListener启动时都做了哪些事?

protocolHandler的初始化是在其父类AbstractProtocol的start方法中完成的,

[html] view plain copy

 print?

  1. public void start() throws Exception {  
  2.     if (getLog().isInfoEnabled())  
  3.         getLog().info(sm.getString("abstractProtocolHandler.start",  
  4.                 getName()));  
  5.     try {  
  6.         endpoint.start();  
  7.     } catch (Exception ex) {  
  8.         getLog().error(sm.getString("abstractProtocolHandler.startError",  
  9.                 getName()), ex);  
  10.         throw ex;  
  11.     }  
  12. }  

调用了endpoint的start方法,这个方法里面做了以下几件事:

(1)设置接收线程数和最大连接数,创建socket

(2)创建线程池,启动监听的线程监听用户请求

(3)启动一个线程来负责异步请求

mapperListener也继承了LifecycleMBeanBase类,也是受生命周期控制的。所以它的启动是在startInternal方法中完成的

[html] view plain copy

 print?

  1. public void startInternal() throws LifecycleException {  
  2.   
  3.        setState(LifecycleState.STARTING);  
  4.   
  5.        // Find any components that have already been initialized since the  
  6.        // MBean listener won't be notified as those components will have  
  7.        // already registered their MBeans  
  8.        findDefaultHost();  
  9.   
  10.        Engine engine = (Engine) connector.getService().getContainer();  
  11.        addListeners(engine);  
  12.   
  13.        Container[] conHosts = engine.findChildren();  
  14.        for (Container conHost : conHosts) {  
  15.            Host host = (Host) conHost;  
  16.            if (!LifecycleState.NEW.equals(host.getState())) {  
  17.                // Registering the host will register the context and wrappers  
  18.                registerHost(host);  
  19.            }  
  20.        }  
  21.    }  

(1)注册已初始化的组件

(2)为各种容器添加监听器

(3)为各种容器建立映射关系

本文转载自:http://blog.csdn.net/aesop_wubo/article/details/7617416

wangxuwei
粉丝 27
博文 342
码字总数 134455
作品 0
杭州
其他
私信 提问
Tomcat源码解读系列(一)——server.xml文件的配置

通过学习Tomcat的源码还可以更加深入地了解JEE规范,学习常见的设计模式。本系列的文章,将会介绍Tomcat的核心功能是如何实现的,一方面作为自己学习的总结,另一方面也希望给学习Tomcat的朋...

heroShane
2014/02/07
241
0
Tomcat处理HTTP请求源码分析(上)

很多开源应用服务器都是集成tomcat作为web container的,而且对于tomcat的servlet container这部分代码很少改动。这样,这些应用服务器的性能基本上就取决于Tomcat处理HTTP请求的connector模...

taote
2011/12/21
710
0
解析TOMCAT框架

毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的。 所以得实践、实践、再实践。 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动过程。 如...

晨曦之光
2012/04/10
795
0
让面试官颤抖的Tomcat系统架构系列!

前言 俗话说,站在巨人的肩膀上看世界,一般学习的时候也是先总览一下整体,然后逐个部分个个击破,最后形成思路,了解具体细节,Tomcat的结构很复杂,但是 Tomcat 非常的模块化,找到了 To...

Java填坑之路
2018/08/24
0
0
Linux Operation学习------Tomcat

1、安装部署Tomcat服务器 1.1使用RPM安装JDK环境 [root@svr5 ~]# yum –y install java-1.8.0-openjdk #安装JDK [root@svr5 ~]# yum –y install java-1.8.0-openjdk-headless #安装JDK [ro......

dscp_linux
2018/01/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
8
0
linux 命令-文本比较comm、diff、patch

本文原创首发于公众号:编程三分钟 今天学了三个文本比较的命令分享给大家。 comm comm 命令比较相同的文本 $ cat charabc$ cat chardiffadc 比如,我有两个文件char和chardiff如上,...

编程三分钟
今天
9
0
QML教程

https://blog.csdn.net/qq_40194498/article/category/7580030 https://blog.csdn.net/LaineGates/article/details/50887765...

shzwork
今天
7
0
HA Cluster之5

对于使用heartbeat v2版的CRM配置的集群信息都是保存在一个名为cib.xml的配置文件中,存放在/var/lib/heartbeat/crm/下。CIB:Cluster Information Base,由于xml文件配置不是那么方便,所以...

lhdzw
今天
8
0
玩转Redis-Redis基础数据结构及核心命令

  《玩转Redis》系列文章主要讲述Redis的基础及中高级应用,文章基于Redis5.0.4+。本文主要讲述Redis的数据结构String,《玩转Redis-Redis基础数据结构及核心命令》相关操作命令为方便对比...

zxiaofan666
今天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部