Jetty的工作原理解析
Jetty是另一个比较看好的Servlet
容器,它的架构比较简单,是一个可拓展性强且非常灵活的应用服务器。它采用Handler作为基本的数据模型,所有可以被扩展的组件都可以作为一个Handler添加到Server中,Jetty会管理这些Handler
Jetty的基本架构
整个Jetty的核心由Server和Connector两个组件构成,整个Server组件是基于Handler容器工作的,它类似于Tomcat的Container容器。jetty的Connector组件负责接收客户端请求,并将请求分配给一个处理队列去执行
jetty核心是围绕着Server类来构建的,Server类继承了Handler,关联了Connector。jetty的Server扩展主要是实现了一个Handler并将Handler添加到Server中,在Server中提供了调用这些Handler的访问规则
jetty的所有组件生命周期管理是基于观察者模式设计的,它和Tomcat的管理是类似的,也有一个LifeCycle
类
每一个组件都会持有一个观察者(这里是Listener
类),当start,stop或fail等事件被触发时,这些Listener将会被调用
Handler的体系结构分为如下两种:
HandlerWrapper
,它可以将一个Handler委托给另一个类去执行,比如我们要将一个Handler加到Jetty中,那么就必须将这个Handler委托给Server去调用HandlerCollection
,这个Handler类可以将多个Handler组装在一起,构成一个Handler链,方便扩展
Jetty的启动流程
Jetty的入口就是Server类,Server类启动完成了,就代表Jetty可以为你提供服务了,具体提供哪些服务主要是看Server类启动时都调用了其他哪些组件的Start方法,实际上配置Jetty就是将这些组件配置到Server上,接着当Jetty启动时就会调用这些组件的Start方法。因为所有的组件都会继承LifeCycle
,所以Server的start方法就会调用所有已经注册到Server的组件。
Server的启动顺序是:首先启动设置到Server的Handler,通常这个Handler会有很多之Handler,这些Handler将组成一个Handler链,Server会依次启动这个链条上所有的Handler,接着会启动 注册在Server上JMX
(Java管理扩展)的Mbean
,让Mbean
也一起工作,最后会启动Connector,打开端口,接收客户端请求
Jetty工作模式
Jetty作为一个独立的Servlet
引擎,可以独立提供Web服务,但是它也可以与其他Web服务器集成,甚至可以将Jetty嵌入应用中,这种方式也较为常见(SpringBoot)。所以它大致是基于两种协议工作的,一种是HTTP
,另一种是AJP
。如果将Jetty集成到Jboss
(集成到Jboss的可能性比较大,而且官网上也有jetty-jboss模块方便集成Jboss),那么就可以让Jetty基于AJP
模式工作
所谓AJP
协议就是为了不同服务器之间可以调用所使用的协议
基于HTTP工作
也就是当Jetty接收到一个请求时,必须按照HTTP解析请求和封装返回的数据,默认情况下Jetty是基于NIO
进行处理的
基于AJP工作
有些web架构不是将Java的应用服务器直接暴露给调用者,而是在应用服务器(如集成了Jetty的Jboss)的前面再加一个Web服务器(如Apache或者Nginx),可以在这个Web服务器做日志分析,负载均衡,权限控制,防止恶意请求以及静态资源预加载等等
在这种架构中,通常是将Tomcat/Jetty与Jboss进行集成,也就是说Jboos中处理Servlet的都交给Tomcat/Jetty这些Servlet容器去处理,而其他的JavaEE组件则由自身去处理
基于AJP工作的Jetty就不需要解析和封装HTTP,因为HTTP的解析工作已经让Apache或者Nginx服务器上完成了,这种方式能加快请求的响应速度
实际上AJP处理请求相比较于HTTP唯一不同就是在读取到Socket数据包时如何来转换这个数据包,按照HTTP的包格式来解析就是基于HTTP工作,用的解析类是HtttpParser类;安装AJP来解析就是基于AJP工作,用的解析类是Ajp13Parserer类
处理请求
当Jetty接收到一个请求时,Jetty就把这个请求交给在Server中注册的代理Handler去执行,如何执行注册的Handler由你决定,Jetty要做的就是调用你注册的第一个Handler的handler方法,我们所要做的就是实现一个自己的Handler,并将其注册到Server上后,整个Server会存在一个Handler链,接着Jetty会执行Handler链的handler方法
在处理请求中Jetty有一种ScopeHandler的处理规则,ScopeHandler类可以拦截Handler的执行,在调用Handler之前或之后做一些额外的事。例如ServletContextHandler,SessionHandler和ServletHandler都继承了ScopeHandler,那么这三个类就组成了一个Handler链,它们的执行规则是:ServletContextHandler.handler->ServletContextHandler.doScope->SessionHandler.doScope->ServletHandler.doScope->ServletContextHandler.doHandle->SessionHandler.doHandle->ServletHandler.doHandle
,我们可以在doScope阶段做一些额的工作
与Tomcat比较
Tomcat与Jetty都作为Servlet引擎,各有优缺点
架构比较
从架构来说,Jetty要比Tomcat更加简单
Jetty的所有组件都是基于Handler来实现的,当然它也支持JMX,但是主要的功能扩展都可以用Handler来实现。可以说Jetty是面向Handler的架构,就像Spring是面向Bean‘的架构,MyBatis是面向Statement的一样,而Tomcat是以多级容器构建起来的
从设计模式来说,Handler的设计就是一个责任链模式,接口HandlerCollection可以帮助开发者构建一个链,而另一个接口ScopeHandler可以帮助开发者控制这个链条的访问顺序。另一个设计模式就是观察者模式,采用这个模式控制Jetty的整个生命周期,只要继承了LifeCycle接口,对象就可以交给Jetty来统一管理了,所以扩展Jetty非常简单。Jetty可以很容易地被扩展和裁剪。相比较而言,Tomcat比较臃肿,Tomcat的整体设计很复杂,Tomcat采用的多级容器的方式是为了更好地扩展,但是这种方式将内部结构暴露给使用者,是的想要扩展Tomcat,开发者必须要首先了解Tomcat的整体设计架构,然后才能按照它的规范来做扩展,无形中增加了学习成本。实际上Tomcat也有采用责任链的设计方式,像Pipeline的Value设计,也是与Jetty的Handler类似的方式,要自己实现一个Value与实现一个Handle难度不相上下
从表面上看,Tomcat的功能要比Jetty强大,因为Tocmat已经帮你做了很多工作,而Jetty只是告诉你能怎么做,如何做有由你去实现
性能比较
Tomcat在处理少数非常繁忙的连接上更有优势,也就是说连接的生命周期如果短,Tomcat的总体性能更高
而Jetty刚好相反,Jetty可以同时处理大量连接而且可以长时间保持这个连接。例如一些Web聊天应用非常适合Jetty做服务器
由于Jetty的架构简单,做为服务器可以按需加载组件,一些不需要的组件可以去掉,无形中可以减少服务器本身的内存开销,处理一次请求也可以减少产生的临时对象,这样性能也会提高。另外,Jetty默认采用NIO技术,在处理I/O请求上更占优势,Tomcat默认使用BIO,在处理静态资源时Tomcat性能较差
特性比较
作为一个标准的Servlet引擎,他们都支持标准的Servlet规范,还有Java EE的规范也都支持。因为Tomcat使用的更为广泛,它对这些支持的会更加全面一些,很多特性Tomcat都直接集成进去了。但是Jetty反应更加快速,一方面是Jetty开发社区更加活跃,另一方面Jetty的修改更加简单,所以对于一些新特性Jetty支持比较快速,而Tomcat在整体结构上要复杂很多,修改也比较缓慢,所以对于一些新特性会慢些
总体来说,二者在特性支持上差别不是很大