【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
引言
Jetty相较于Tomcat更加轻便,虽然架构更加简单,但是看起来可并不轻松。Spring是设计初衷是用来管理应用中的实例Bean,因而是基于Bean的架构;Jetty则更倾向于流程和组件的管理,采用了基于handler的架构。handler的嵌套和链式结构,LifeCycle和doStart、doHandler模式无不印证了这点。
本文主要从基本架构、LifeCycle结构、Handler体系结构、Jetty启动过程、接受并处理请求的流程和与Tomcat的比较来简要介绍下Jetty,细节部分后面的博文会有分析。
Jetty的基本架构
前面的博文谈及应用服务期的架构已经说过了几个基本模块的概念,connection、Threadpool等~拷贝了许令波画的图(文中关于基本架构的描述挺详细的,参考了其目录结构哈~不过对于有些知识点有自己的看法,因此总结该文):
该博文中谈到“Jetty 中还有一些可有可无的组件,我们可以在它上做扩展。如 JMX,我们可以定义一些 Mbean 把它加到 Server 中,当 Server 启动的时候,这些 Bean 就会一起工作。”我的理解是,Jetty中的JMX是提供给server的Container,使得注册到server的Handler同时注册到JMX上,以便于运行时的监控和管理,应该是先有server再有JMX,而不是反过来的。
LifeCycle体系结构
Jetty是基于Handler的架构模式,对于组件化的概念很容易理解,那Jetty又是如何管理流程和Handler的生命周期的呢,这就需要从下节的Handler的体系架构来解释,本节主要分析LifeCycle。
写文档最讨厌的就是画图,无奈有些图没法copy~
上图包含四层涵义:
1、每个Handler都是一个LifeCycle
2、AggregateLifeCycle正如起名,聚集在一起的生命周期。Jetty把Handler生命周期所关联的一些subHandler注册在Hahdler上,eg:server->deployManager正是如此。
3、监听器的概念就是一个观察者模式的应用,触发于Handler的doStart,doStop,doFail等事件。
4、Jetty的LifeCycle结构主要影响Jetty的初始化,而Handler结构影响Jetty的处理功能。
Handler体系结构
既然Jetty是基于Handler的架构,那么Handler体系关乎着Jetty的方方面面:
上图有几层涵义:
1、红色的server即Jetty的核心Handler,它依赖的几个类虽然不是Handler,也在图中标出以方便理解,server需要Deploy部署,需要Connector,自然需要inner Handler,这里的红色的虚线是默认的依赖关系,嵌入式的Jetty或自定义情况下是可以变的,比如换成ResourceHandler,WebAppContext等~
2、AbatractHandlerContainer提供对嵌套Handler获取Childs的方法支持,因此位于很顶层。
3、ContextHandlerCollection不同于普通的HandlerCollection的区别在于,提供了对于Context的支持,即依据生产的app建立app与name的映射关系并对于url请求依据该映射关系分发到指定的app中。
4、HandlerWrapper仅仅提供了简单的对于Wapper的handler等操作,其实handler操作并不是主要的,Jetty中主要是用它来创建Handler的嵌套结构,就如ScopedHander一样,而handler操作大多数时候无用。
5、ScopedHandler这个真是折腾我好久,这样设计的意图着实不好理解,后面有专题解释,为理解本文,你可以将实现了继承了该类的Handler理解成已经是一个完整的嵌套Handler即可。
6、ContextHandler从图中可以看到,由DeployManager生产,并和ServletHandler等构成了嵌套Handler。ContextHandler的本质可理解为ServletContext,取到ServletContext,由于嵌套Handler的构造继而会调用ServletHandler等初始化和相关操作,最后走到web应用中处理业务代码。其实这个嵌套关系是可以修改的,比如应用中用不到sessionHandler,完全可以将其删除掉,但问题在与这种关系写在了代码中,为什么就不能留在配置文件中呢?也许配置文件也可以,没有验证过。
Jetty的启动过程
实际流程比较复杂,上面的时序图是个简化版本。启动的时序图有几点需要注意:
1、红线部分的第一次其实并没有handler,因为没有生产webappcontext,第二次再次调用start的时候才真的运作
2、蓝线部分描述的就是app的生产到contextHandler的生产的过程,后面的contextHandler的初始化是由于deployManager注册了事件监听器触发的。
3、最后打开Http连接,监听请求的到来
接受请求
由于Jetty默认采用NIO的方式接受请求,本文基于NIO的方式简单介绍下实现原理,因为NIO内容比较多,会在下面的文章中给出总结。
处理请求
主要介绍jetty接收到请求后如何生产并解析Request,Response等属性并最终走到handler方法体内。
这里面涉及到的connection有多个,SelectorChannelConnector、SelectorChannelEndPoint、AsyncHttpConnection,功能各不相同,下面NIO章节会详细总结。
Jetty与Tomcat的区别
由于没有研究过Tomcat,所以区别不好说,这里暂时就网上的一些言论和自己所了解到的一些总结下(摘自于许令波)。
Jetty 的架构从前面的分析可知,它的所有组件都是基于 Handler 来实现,当然它也支持 JMX。但是主要的功能扩展都可以用 Handler 来实现。可以说 Jetty 是面向 Handler 的架构,就像 Spring 是面向 Bean 的架构,iBATIS 是面向 statement 一样,而 Tomcat 是以多级容器构建起来的,它们的架构设计必然都有一个“元神”,所有以这个“元神“构建的其它组件都是肉身。
从设计模板角度来看 Handler 的设计实际上就是一个责任链模式,接口类 HandlerCollection 可以帮助开发者构建一个链,而另一个接口类 ScopeHandler 可以帮助你控制这个链的访问顺序。另外一个用到的设计模板就是观察者模式,用这个设计模式控制了整个 Jetty 的生命周期,只要继承了 LifeCycle 接口,你的对象就可以交给 Jetty 来统一管理了。所以扩展 Jetty 非常简单,也很容易让人理解,整体架构上的简单也带来了无比的好处,Jetty 可以很容易被扩展和裁剪。
相比之下,Tomcat 要臃肿很多,Tomcat 的整体设计上很复杂,前面说了 Tomcat 的核心是它的容器的设计,从 Server 到 Service 再到 engine 等 container 容器。作为一个应用服务器这样设计无口厚非,容器的分层设计也是为了更好的扩展,这是这种扩展的方式是将应用服务器的内部结构暴露给外部使用者,使得如果想扩展 Tomcat,开发人员必须要首先了解 Tomcat 的整体设计结构,然后才能知道如何按照它的规范来做扩展。这样无形就增加了对 Tomcat 的学习成本。不仅仅是容器,实际上 Tomcat 也有基于责任链的设计方式,像串联 Pipeline 的 Vavle 设计也是与 Jetty 的 Handler 类似的方式。要自己实现一个 Vavle 与写一个 Handler 的难度不相上下。表面上看,Tomcat 的功能要比 Jetty 强大,因为 Tomcat 已经帮你做了很多工作了,而 Jetty 只告诉,你能怎么做,如何做,有你去实现。
单纯比较 Tomcat 与 Jetty 的性能意义不是很大,只能说在某种使用场景下,它表现的各有差异。因为它们面向的使用场景不尽相同。从架构上来看 Tomcat 在处理少数非常繁忙的连接上更有优势,也就是说连接的生命周期如果短的话,Tomcat 的总体性能更高。
而 Jetty 刚好相反,Jetty 可以同时处理大量连接而且可以长时间保持这些连接。例如像一些 web 聊天应用非常适合用 Jetty 做服务器,像淘宝的 web 旺旺就是用 Jetty 作为 Servlet 引擎。
另外由于 Jetty 的架构非常简单,作为服务器它可以按需加载组件,这样不需要的组件可以去掉,这样无形可以减少服务器本身的内存开销,处理一次请求也是可以减少产生的临时对象,这样性能也会提高。另外 Jetty 默认使用的是 NIO 技术在处理 I/O 请求上更占优势,Tomcat 默认使用的是 BIO,在处理静态资源时,Tomcat 的性能不如 Jetty。
来源:oschina
链接:https://my.oschina.net/u/947581/blog/110553