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在整体结构上要复杂很多,修改也比较缓慢,所以对于一些新特性会慢些

总体来说,二者在特性支持上差别不是很大

posted @ 2021-02-16 15:02  OverZeal  阅读(1257)  评论(0编辑  收藏  举报