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

java特种兵读书笔记(4-4)——java通信之tomcat对IO请求的处理

2016-01-21 16:05 465 查看
tomcat配置

tomcat的配置体系,如Server,Service,Executor,HTTP等。这是tomcat从外层到内层的访问机制。

tomcat启动时,是启动java的main方法。tomcat的lib目录下有一个catalina的jar包,引导方法main就在这个jar包的BootStrap类中,用jps等命令可以在JVM进程中看到。

跟踪源码会发现,系统启动时会相继的

①启动Server,Tomcat中对应类是StandardServer

②设置Listener信息,相继调用initialize方法,该方法用于启动Service,对应Tomcat中的StandardService

③在StandardService初始化方法中开始初始化Connector,Engine等相关信息

Connector配置

配置Connector时会设置protocol协议,有HTTP/1.1,AJP/1.3等等。它们表示tomcat会使用哪一种协议来处理请求,对应到代码里即哪一套程序来处理IO请求。

源码在Connector类的setProtocol方法中。

如果要tomcat支持NIO,我们可以传入Http11NioProtocol这个协议。

每一种协议都有一个XXXEndPoint属性。

①XXXProtocol调用init初始化方法,创建SocketFactory,并设置到XXXEndPoint中。

②调用XXXEndPoint的init方法,设置acceptorThreadCount,标识接受请求的线程数(可以有多个线程同时接受请求,默认是1,一般不用修改)。

③创建SocketServer对象。

④系统开始启动start方法(前面说的系统自动关联的一系列操作),最后会调用到XXXProtocol的start方法,并接着调用XXXEndPoint的start方法。

XXXEndPoint的start方法——创建socket+创建默认线程池(组)

①在没有设置Executor时创建一个线程组来处理请求(数组管理线程,不是java本身的ThreadGroup)。Executor的单独配置在server.xml中。

②接受请求的线程启动起来,它们仅仅用于接受请求。线程启动后的动作取决于启动时传入的任务new Thread(new Acceptor(...));

③Acceptor类——初始化:

通过serverSocketFactory对象的acceptSocket方法间接调用ServerSocket的accept方法,得到一个socket连接。

④Acceptor类——线程的使用

processSocket方法对socket进行处理,如果配置了线程池,会使用配置的Executor提交SocketProcess(把socket封装成实现Runnable接口的任务类)去执行。如果没有配置线程池,则会使用先前提到过的线程组来处理。如果线程组内有闲置线程,分配一个处理;若没有闲置线程,会创建一个线程处理,在任务结束后(线程不会结束),会将当前线程放入workers线程组(定义的存放在数组中的线程)中。

request和response

分配线程的类是XXXEndPoint类的一个内部类Worker。

①setSocketOptions方法:设置socket的相关参数,比如TcpNoDelay,SoTimeout等参数。

②XXXProtocol的XXXConnectionHandler的process方法:首先会去获取一个XXXProcessor对象,如果没有获取,会创建一个新的。该XXXProcessor对象是ActionHook的实现类,会调用ActionHook的action方法。

拉模式与推模式

用浏览器访问解释,用户需要什么信息就去访问,那么就是拉取。如果一打开浏览器,就弹出了一大堆页面,就是推送。推送一般不关心反馈,类似于群发短信的方式。

推模式响应更加及时,因为不等你去拉,我这边准备好了或者有什么信息就告诉你,可能等你需要并且拉的时候,这个信息已经都是很陈旧的信息了。

推送方式的几种实现:

①每个客户端每隔很短的时间就去请求服务器一次,获取最新信息。但是这样有缺点,会有很多请求是浪费的,因为客户端不知道什么时候该去获取数据,可能获取的时候数据还没准备好;或者已经获取过了,不需要再获取了,但是这之后还是会发请求,服务端也会应答。

如果这些请求都打在服务器的数据库上,对服务器压力很大。如果基于C/S模式,每个浏览器的每个选项卡每隔5秒钟都要请求服务器一次,那么请求量会成倍的上涨。

②真正的推送:当信息真正发生变化的时候,触发被改变的内容去通知每个终端,也许会直接将数据交给终端,也许只是一个通知,让客户端决定是否要去获取对应的数据或者做相应操作。

长连接与推送

要完成推送, 客户端和服务器端的连接是长连接,理论上长连接是不断开的一种连接,在web层面最简单的方式,是不断开response输出流(comet启用后就不会调用finishResponse方法)。不断开的response输出内部处理很复杂,但是现在很多开源框架已经实现。

长连接建立后,服务器对消息的处理有主动性,消息可以由服务器端准备好,放入内存,不用针对每个请求去分配内存。

长连接进来以后,需要解决的就是连接与线程的解耦问题,因为这样已经不是一个请求对应一个线程了,因为一个线程可能会操作多个连接,所以前面提到的非阻塞IO的引入是必然的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: