您的位置:首页 > 运维架构 > Tomcat

Tomcat7-Connector(连接器)学习

2016-09-04 20:41 471 查看
comment:本文基于Tomcat7.0.68

Connector作用定位

源码内部实现
Connect类图关键属性和方法
协议处理器

Connector构造方法

Connector工作流程
初始化和启动

请求处理

最后一张图总结下Connector的处理流程

参考

Tomcat架构:



Connector作用&定位

根据官方文档,解释如下:

Connect(连接器)负责接收外部连接请求,创建Request、Response对象用于请求的数据交换,并分配线程让Container处理该请求。

官方文档 https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

Connector可以支持多种协议的请求(如HTTP,AJP等)的请求,对Connector的配置在conf/server.xml中

默认为:

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />


即在tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3

源码内部实现

Connect类图关键属性和方法:



其中,ProtocalHandler是协议处理器接口,不同的协议各自实现。Service是由一个或多个Connector共享一个Container组成,对外部请求提供服务,service主要为了关联Connector和Container。关于Service,请移步。 Adapter是基于coyote的servlet容器的入口。

协议处理器

上文说到,Connector支持多种协议的请求,必然需要进行协议的解析等处理,ProtocalHandler类层次结构为:



从类图中看到,协议上有三种不同的实现方式:JIO、APR、NIO

关于协议的更多,请移步:

在Connector的代码中:

/**
* Coyote Protocol handler class name.
* Defaults to the Coyote HTTP/1.1 protocolHandler.
*/
protected String protocolHandlerClassName =
"org.apache.coyote.http11.Http11Protocol";


可以看到,默认采用http1.1协议

Connector构造方法

public Connector() {
this(null);
}
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);
}
}


上述代码中根据协议名称构造Connector,继续进入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为null(还记得在哪里设置的吗?conf/server.xml),则setProtocol什么都没做。但是上文中提到,代码初始化protocolHandlerClassName了。

回到构造方法,接下来会加载以protocolHandlerClassName为名字的类,并创建对象实例。至此,构造方法完成。

Q 怎么更换默认的protocolHandler?

A 自己实现ProtocolHandler,再setProtocolHandlerClassName设置为自定义类。

Q 可以在server.xml自定义协议(如xxx),自定义xxx协议的处理器吗?

A 待check……

Connector工作流程

初始化和启动

时序图:



1. Tomcat初始化时会调用Bootstrap的Load方法,会调用Connector的构造方法(已在上文中分析)。

2. 接着调用server.init(),调用链会走到Connector的initInternal()方法

protected void initInternal() throws LifecycleException {
super.initInternal();
adapter = new CoyoteAdapter(this);//connector作为参数传入,设置到CoyoteAdapter的属性中
protocolHandler.setAdapter(adapter);//adapter设置到protocolHandler协议处理器的属性中
//……忽略非核心代码

protocolHandler.init();
//AbstractHttp11JsseProtocol.init()生成JSSEImplementation实例,接着调用AbstractProtocol.init()方法, 进而进入AbstractEndpoint.init(),再调用JIoEndpoint.bind()**核心方法,下面细说**

mapperListener.init();//初始化mapperListener,只是调用了父类(LifecycleMBeanBase)的initInternal,非核心
}


JIoEndpoint.bind()中,会设置Acceptor线程数为1,设置最大连接数(default 200),设置最大连接数的时候会初始化connectionLimitLatch(用于控制Connector的并发连接数,其值即为最大连接数),并初始化serverSocketFactory创建serverSocket。 Acceptor线程在start的时候细说。

protected void startInternal() throws LifecycleException {
……忽略非核心代码

protocolHandler.start();//调用AbstractProtocol.start()进而进入AbstractEndpoint.start()在调用JIoEndpoint.startInternal()方法核心,见下文

mapperListener.start(); //见下文
}


3.接着调用server.start(),调用链会走到Connector的startInternal()方法

4. JIoEndpoint.startInternal()所做的事情:

- 创建工作线程池: 其参数如下:corePoolSize=10,maximumPoolSize=200,keepAliveTime=60s

- 如果在init阶段未初始化ConnectionLatch,则此时会进行初始化

- 启动Acceptor线程(启动的个数在init中初始化了,default 1)监听的serverSocket上的请求(关于该线程的更多,请移步 http://blog.csdn.net/cx520forever/article/details/52441543 )

- 启动一个异步timeout线程(关于该线程的更多,请移步http://blog.csdn.net/cx520forever/article/details/52496079 )

- 再附一张 JIoEndpoint.startInternal()的时序图

-


5. mapperListener.start()

前文说到Connector的属性,有两个属性未列举,mapper和mapperListener

mapper维护了一个从Host到Wrapper的各级容器的快照,即容器的信息,在org.apache.catalina.connector.Request进入Container容器前,Mapper会根据这次请求的hostname和contextPath将host和context容器设置到Request的mappingData属性中。

MappingListener注册到Engine,Host各级容器上,容器状态发生变化就通知它变化更新到Mapper中。

根据Mapper可以确定将请求分派到哪个Host和哪个Servlet容器上以及哪个Servlet上,在传到Servlet前,通过Filter链并在这个过程中调用可能的Listener,最终执行Servlet的service方法。

请求处理

前文中说到Acceptor线程会监听Socket请求并转发给工作线程池,处理请求的即JIoEndpoint的内部类
SocketProcessor


SocketProcessor根据socket的状态进行第一层处理,另外SSL的握手也是由它负责,在处理时又调用
handler.process(socket, SocketStatus.OPEN_READ);
,Hanlder接口是每个具体的Endpoint的内部接口,一般由对应Protocol的一个Handler内部类实现,比如JIoEndponit的handler对应的就是Http11Protocol的Http11ConnectionHandler。

查看handler的调用链,会到
adapter.service(request, response);
,CoyoteAdapter完成http request的解析和分派,进而调用
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
,这样,Connector就把请求传递到了Container,也就是Engine对应Pipeline的第一个Valve的invoke方法。关于Pipeline & Valve机制,参考本人另一篇博客:pipeline-valve机制

最后一张图总结下Connector的处理流程:

缺省状态(BIO)下HTTP connector的架构及其消息流:



CoyoteAdapter对象负责将http request解析成HttpServletRequest对象,之后绑定相应的容器,然后从engine开始逐层调用valve直至该servlet。

Http11Protocol 类完全路径org.apache.coyote.http11.Http11Protocol,这是支持HTTP的BIO实现。Http11Protocol包含了JIoEndpoint对象及Http11ConnectionHandler对象,她维护了一个Http11Processor对象池,Http11Processor对象会调用CoyoteAdapter完成HTTP Request的解析和分派。

附上一张Tomcat的Connector组件工作具体序列图:



参考

http://www.cnblogs.com/hansongjiang/p/4229756.html

http://www.cnblogs.com/hansongjiang/category/628889.html

http://blog.csdn.net/aesop_wubo/article/details/7617416

http://www.programgo.com/article/24913246630/

https://yq.aliyun.com/articles/20175

http://blog.csdn.net/fjslovejhl/article/details/20375359

http://blog.csdn.net/fjslovejhl/article/details/22090885 LimitLatch

http://www.360doc.com/content/16/0612/19/1073512_567216241.shtml 实际问题

http://blog.csdn.net/Zerohuan/article/details/50752635#t11

http://blog.csdn.net/c929833623lvcha/article/details/44677569
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息