任何一个Handler都需要关联一个Server组件,也就是说Handler需要被Server组件来管理。一般来说Handler会加载一些资源到内存,因此通过设置destroy方法来销毁。
Handler继承关系
Handler只是一个接口,完成具体功能的还是它的子类。那么Handler有哪些子类呢?它们的继承关系又是怎样的?这些子类是如何实现Servlet容器功能的呢?
Jetty中定义了一些默认Handler类,并且这些Handler类之间的继承关系比较复杂,我们先通过一个全景图来了解一下
Handler接口之下有抽象类AbstractHandler,之下有AbstractHandlerContainer,为什么需要这个类呢?
过渡,为实现链式调用,一个Handler内部必然要有其他Handler的引用,所以这个类的名字里才有Container。
- HandlerWrapper和HandlerCollection都是Handler,但这些Handler里还包括其他Handler的引用
- HandlerWrapper只包含一个其他Handler的引用,而HandlerCollection中有一个Handler数组的引用。
HandlerWrapper有两个子类:
Server
Handler模块的入口,必然要将请求传递给其他Handler来处理,为了触发其他Handler的调用,所以它是一个HandlerWrapper。
ScopedHandler
实现了“具有上下文信息”的责任链调用。Servlet规范规定Servlet在执行过程中有上下文。这些Handler在执行过程中就是通过ScopedHandler来实现的获得上下文。
ScopedHandler有一堆的子类用来实现Servlet规范,比如ServletHandler、ContextHandler、SessionHandler、ServletContextHandler和WebAppContext
HandlerCollection
维护了一个Handler数组。因为Jetty可能需要同时支持多个Web应用,如果每个Web应用有一个Handler入口,那么多个Web应用的Handler就成了一个数组,比如Server中就有一个HandlerCollection,Server会根据用户请求的URL从数组中选取相应的Handler来处理,就是选择特定的Web应用来处理请求。
Handler的类型
协调Handler
负责将请求路由到一组Handler中去,比如HandlerCollection,它内部持有一个Handler数组,当请求到来时,它负责将请求转发到数组中的某一个Handler。
过滤器Handler
自己会处理请求,处理完了后再把请求转发到下一个Handler,比如HandlerWrapper,它内部持有下一个Handler的引用。
所有继承了HandlerWrapper的Handler都具有了过滤器Handler的特征,比如ContextHandler、SessionHandler和WebAppContext等。
内容Handler
这些Handler会真正调用Servlet来处理请求,生成响应内容,比如ServletHandler。
如果浏览器请求的是一个静态资源,也有相应的ResourceHandler来处理这个请求,返回静态页面。
实现Servlet规范
上文提到,ServletHandler、ContextHandler以及WebAppContext等,它们实现了Servlet规范,那具体是怎么实现的呢?为了帮助你理解,在这之前,我们还是来看看如何使用Jetty来启动一个Web应用。
//新建一个WebAppContext,WebAppContext是一个Handler WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/mywebapp"); webapp.setWar("mywebapp.war"); //将Handler添加到Server中去 server.setHandler(webapp); //启动Server server.start(); server.join();
上面的过程主要分为两步:
第一步创建一个WebAppContext,接着设置一些参数到这个Handler中,就是告诉WebAppContext你的WAR包放在哪,Web应用的访问路径是什么。
第二步就是把新创建的WebAppContext添加到Server中,然后启动Server。
WebAppContext对应一个Web应用。我们回忆一下Servlet规范中有Context、Servlet、Filter、Listener和Session等,Jetty要支持Servlet规范,就需要有相应的Handler来分别实现这些功能。因此,Jetty设计了3个组件:ContextHandler、ServletHandler和SessionHandler来实现Servlet规范中规定的功能,而WebAppContext本身就是一个ContextHandler,另外它还负责管理ServletHandler和SessionHandler。
我们再来看一下什么是ContextHandler。ContextHandler会创建并初始化Servlet规范里的ServletContext对象,同时ContextHandler还包含了一组能够让你的Web应用运行起来的Handler,可以这样理解,Context本身也是一种Handler,它里面包含了其他的Handler,这些Handler能处理某个特定URL下的请求。比如,ContextHandler包含了一个或者多个ServletHandler。
再来看ServletHandler,它实现了Servlet规范中的Servlet、Filter和Listener的功能。ServletHandler依赖FilterHolder、ServletHolder、ServletMapping、FilterMapping这四大组件。FilterHolder和ServletHolder分别是Filter和Servlet的包装类,每一个Servlet与路径的映射会被封装成ServletMapping,而Filter与拦截URL的映射会被封装成FilterMapping。
SessionHandler从名字就知道它的功能,用来管理Session。除此之外WebAppContext还有一些通用功能的Handler,比如SecurityHandler和GzipHandler,同样从名字可以知道这些Handler的功能分别是安全控制和压缩/解压缩。
WebAppContext会将这些Handler构建成一个执行链,通过这个链会最终调用到我们的业务Servlet。我们通过一张图来理解一下。
通过对比Tomcat的架构图,你可以看到,Jetty的Handler组件和Tomcat中的容器组件是大致是对等的概念,Jetty中的WebAppContext相当于Tomcat的Context组件,都是对应一个Web应用;而Jetty中的ServletHandler对应Tomcat中的Wrapper组件,它负责初始化和调用Servlet,并实现了Filter的功能。
对于一些通用组件,比如安全和解压缩,在Jetty中都被做成了Handler,这是Jetty Handler架构的特点。
因此对于Jetty来说,请求处理模块就被抽象成Handler,不管是实现了Servlet规范的Handler,还是实现通用功能的Handler,比如安全、解压缩等,我们可以任意添加或者裁剪这些“功能模块”,从而实现高度的可定制化。
总结
Jetty的Connector只支持NIO模型,跟Tomcat的NioEndpoint组件一样,它也是通过Java的NIO API实现的。
在线程模型设计上Tomcat的NioEndpoint跟Jetty的Connector是相似的,都是用一个Acceptor数组监听连接,用一个Selector数组侦测I/O事件,用一个线程池执行请求。它们的不同点在于,Jetty使用了一个全局的线程池,所有的线程资源都是从线程池来分配。
Jetty Connector使用回调函数模拟异步I/O,比如Connection向EndPoint注册了一堆回调函数。它的本质将函数当作一个参数来传递,告诉对方,你准备好了就调这个回调函数。