不论Tomcat的容器设计得如何精妙,本质上Tomcat就是个http服务器,须要从socket中得到HTTP数据流;另外一方面,容器只能处理封装好的org.apache.coyote.Request (这个类的具体用途下面会讲到),从socket到Request之间须要有个转换过程。所以,链接socket和容器之间的重任就交给了Coyotehtml
coyote(北美的一种狼、山狗)java
coyote是tomcat的Connector框架的名字,简单说就是coyote来处理底层的socket,并将http请求、响应等字节流层面的东西,包装成Request和Response两个类(这两个类是tomcat定义的,而非servlet中的ServletRequest和ServletResponse),供容器使用;同时,为了能让咱们编写的servlet可以获得ServletRequest,tomcat使用了facade模式,将比较底层、低级的Request包装成为ServletRequest(这一过程一般发生在Wrapper容器一级),这也是为不少人津津乐道的tomcat对设计模式的一个巧妙的运用,具体过程将会在之后讨论。程序员
因此,coyote本质上是为tomcat的容器提供了对底层socket链接数据的封装,以Request类的形式,让容器可以访问到底层的数据。web
而关于链接池、线程池等直接和socket打交道的事情,tomcat交给了org.apache.tomcat.util.net包的类去完成,这里暂且不表apache
http://www.webweavertech.com/costin/archives/000421.html
这个网页很好的描述了coyote的做用和设计思想,并介绍了其中几个影响性能的核心类编程
这个包里面的主要是coyote框架的接口设计模式
“适配器”在这里的意思,是指“凡是使用coyote链接器的容器,都要实现这个接口,以便从coyote链接器接收请求和响应数据”,固然这里的请求和响应是org.apache.coyote.Request和Response数组
每一个ProtocolHandler,表明着对一种协议的支持,好比tomcat默认支持的协议有http1.1和ajp。根据支持的协议,ProtocolHandler里面一般包含了一个实现对应协议的Handler接口的处理类,用于接收socket对象,再交给对应协议的Processor类(然而这个Processor类没有实现Processor接口,而是实现了ActionHook接口),最后由Processor类交给实现了Adapter接口的容器(准确的说是该容器的Pipeline的第一个Valve)tomcat
这个接口已经废弃了,一般tomcat的Processor实现类实现的接口是ActionHook。你会看到许多名为“XXXProcessor”的类,但其实他们实现的接口倒是ActionHook服务器
本接口代替了Processor接口,成为全部Processor实现类的标准接口。其方法只有一个:public void action( ActionCode actionCode, Object param);
ActionCode是一个静态类,说白了是一堆常量(估计之后会改为enum),即对应不一样的ActionCode,ActionHook要做出不一样的动做,至于param是用于传递一些信息的,一般会把调用者“this”传递进去
两个接口都只有一个方法,分别是doread和dowrite,就是把数据从ByteChunk参数读出或者写入ByteChunk。然而“数据”从何而来、怎样写进ByteChunk,还得看不一样的类实现
鉴于其重要性,下面专文讲述
Request这个类可谓tomcat的一大核心,几乎全部connector和容器都要用到它
Request类实现了对底层http字节流的封装,由于http本质上是从网络过来的一串字节流,而且从逻辑上根据http协议,分红了头和体,其中头部又有不少字段(包括MIME字段)。而Request的做用就是把这些字节封装成对应的字段,而且达处处理效率的最优
所以,Request里面大部分方法是字段的get方法(set方法很少,由于大部分字段是不可改变的),此外还有提供给容器使用的方法,如recycle、inputbuffer等等。但最关键的是,Request是如何提升处理效率的
对于底层的、和字节流打交道的DO(data object),性能瓶颈在于对内存的使用上(由于字节都是放在一块块的内存中),若是能有效的使用内存,就能有效地提升DO的性能。
若是让咱们来实现这个Request类,估计大部分人第一反应就是用String来表示每一个http头字段,然而String的效率之低下是绝对没法胜任服务器的性能要求的
Request的注释告诉咱们,它的大部分字段是“GC free”的,即不多、甚至不会被垃圾回收。杜绝了java中最大的一个性能瓶颈,Request天然性能获得大幅提高
此外,其字段的一些耗时操做都会延迟到用户代码一级,也就是说,tomcat内部在使用Request时,都会尽可能保证它的字段处于原始的字节状态(而不是图方便处处使用String),直到用户代码(也就是咱们写的servlet)须要时才进行转换,若是用不到(其实http请求的大部分字段在咱们编程时都用不到),就不做转换。这样又进一步挖掘出更多的性能潜力,其思想和“延迟加载”的设计模式一模一样。
固然,tomcat的程序员也是人也喜欢偷懒,谁都不乐意直接操纵字节数组,那样出错的风险也大。所以,tomcat的org.apache.tomcat.util包定义了许多底层的工具类,用于操做和维护字节数组。Request的字段们的类型为MessageBytes就是其中的一种
而关于Response,原理和Request相似,可是Response简单了不少,最明显的是里面的字段不像Request那样为效率绞尽脑汁,而是直接用了String,也许是Response对总体效率影响不大,亦或者当前版本的tomcat还未对其进行改造