Tomcat7-Connector(连接器)学习
2016-09-04 20:41
471 查看
comment:本文基于Tomcat7.0.68
Connector作用定位
源码内部实现
Connect类图关键属性和方法
协议处理器
Connector构造方法
Connector工作流程
初始化和启动
请求处理
最后一张图总结下Connector的处理流程
参考
Tomcat架构:
Connect(连接器)负责接收外部连接请求,创建Request、Response对象用于请求的数据交换,并分配线程让Container处理该请求。
官方文档 https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
Connector可以支持多种协议的请求(如HTTP,AJP等)的请求,对Connector的配置在conf/server.xml中
默认为:
即在tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3
其中,ProtocalHandler是协议处理器接口,不同的协议各自实现。Service是由一个或多个Connector共享一个Container组成,对外部请求提供服务,service主要为了关联Connector和Container。关于Service,请移步。 Adapter是基于coyote的servlet容器的入口。
从类图中看到,协议上有三种不同的实现方式:JIO、APR、NIO。
关于协议的更多,请移步:
在Connector的代码中:
可以看到,默认采用http1.1协议
上述代码中根据协议名称构造Connector,继续进入setProtocol
如果protocol为null(还记得在哪里设置的吗?conf/server.xml),则setProtocol什么都没做。但是上文中提到,代码初始化protocolHandlerClassName了。
回到构造方法,接下来会加载以protocolHandlerClassName为名字的类,并创建对象实例。至此,构造方法完成。
Q 怎么更换默认的protocolHandler?
A 自己实现ProtocolHandler,再setProtocolHandlerClassName设置为自定义类。
Q 可以在server.xml自定义协议(如xxx),自定义xxx协议的处理器吗?
A 待check……
1. Tomcat初始化时会调用Bootstrap的Load方法,会调用Connector的构造方法(已在上文中分析)。
2. 接着调用server.init(),调用链会走到Connector的initInternal()方法
JIoEndpoint.bind()中,会设置Acceptor线程数为1,设置最大连接数(default 200),设置最大连接数的时候会初始化connectionLimitLatch(用于控制Connector的并发连接数,其值即为最大连接数),并初始化serverSocketFactory创建serverSocket。 Acceptor线程在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方法。
SocketProcessor根据socket的状态进行第一层处理,另外SSL的握手也是由它负责,在处理时又调用
查看handler的调用链,会到
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/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
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.htmlhttp://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
相关文章推荐
- java-模拟tomcat服务器
- i-jetty环境搭配与编译
- 从源码安装Mysql/Percona 5.5
- 实现单Tomcat多Server配置
- 生产环境下的Tomcat配置
- 在kubernetes上实现tomcat日志的持久化
- Linux部署Tomcat服务器
- jenkins------结合maven将svn项目自动部署到tomcat下
- 如何搞定tomcat这只喵~
- 架构纵横谈之二 ---- 架构的模式与要点
- eclipse内安装配置tomcat
- BS项目中的CSS架构_仅加载自己需要的CSS
- 浅析Ruby的源代码布局及其编程风格
- 关于三种主流WEB架构的思考
- mysql 5.7 docker 主从复制架构搭建教程
- Android操作系统的架构设计分析
- asp.net 抓取网页源码三种实现方法