深入Jetty源码之Handler总述

时间:2024-04-01 21:01:12

Handler概述

Handler是Jetty中的核心接口,它用于处理所有连接以外的逻辑,比如对Servlet框架的实现,以及用户自定义的Handler等,它继承自LifeCycle和Destroyable接口,只有一个主要方法:handle,包含Request和Response实例。在深入Jetty源码之Connection中有写道在HttpConnection的handleRequest()方法中会最终调用Server的handle()或handleAsync()方法,并且传入HttpConnection自身作为参数以处理后续逻辑,在这里Server作为Handler的容器,在Server中以HttpConnection为参数的handle()和handleAsync()方法中,会调用向这个Handler容器中注册的所有Handler的handle()方法。即在使用Jetty时,我们首先要向Server注册相应的Handler实例。

Handler接口定义

Handler的接口定义如下:
public interface Handler extends LifeCycle, Destroyable {
    // 处理一个HTTP请求,并最终将响应写入Response中。不同的实现有不同的功能和逻辑,如WebAppContext实现一个Servlet容器,
    
// 而ErrorHandler则向Response中写入一个包含错误码和原因的HTML页面。
    
// 关于参数:
    
// target表示Request的目标,它可以时一个URI或一个名字。即Request中的pathInfo字段。
    
// baseRequest表示在HttpConnection中创建并解析的最初的Request,它没有被包装。
    
// request表示一个HttpServletRequest,它可以同baseRequest相同的实例,也可以是一个经过包装后的HttpServletRequest。
    
// response表示一个HttpServletResponse,它可以是经过包装的HttpServletResponse或在HttpConnection创建的最原始的HttpServletResponse。
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException;
    
    public void setServer(Server server);
    public Server getServer();
    
    public void destroy();
}

Handler类图

深入Jetty源码之Handler总述

AbstractHandler

AbstractHandler继承自AggregateLifeCycle并实现了Handler接口,是基本上所有Handler的基类。它的实现也非常简单,它定义了Server成员,并实现了getServer和setServer方法,在setServer实现中,如果已存在的Server引用和新设置的Server不同,则先将自身从已存在的Server的Container中移除,然后将自身添加到新的Server的Container中,并更新内部对Server的引用实例。在destroy方法中,也会将自身从Server引用实例的Container中移除。

DefaultHandler

DefaultHandler直接继承自AbstractHandler,它可以用于Handler链表的末尾Handler,用于处理所有不能被其他Handler处理的请求:/favicon.ico -> 显示jetty图标,/ -> 显示404错误页面,并列出所有可用的ContextPath,任何其他请求显示404错误页面。图标的显示和可用ContextPath的列表显示都是可配的。

DumpHandler

DumpHandler直接继承自AbstractHandler,用于测试和调试,显示Request消息内容。它显示的信息有PathInfo、ContentType、CharacterEncoding、RequestLine、Headers、Parameters、CookieName、Cookies、Attributes、Content等。

ErrorHandler

ErrorHandler直接继承自AbstractHandler,用于处理错误页面,使用ContextHandler.setErrorHandler()或Server.addBean()注册。它显示出错代码、原因以及更详细的信息。其中异常栈从Request的javax.servlet.errro.exception中获取。

ErrorPageErrorHandler

ErrorPageErrorHandler继承自ErrorHandler,它可以配置不同的Exception和Response Status Code到不同的页面。Exception类型从Request中的javax.servlet.error.exception_type或javax.servlet.error.exception属性中获取,Response Status Code从Request中的javax.servlet.error.status_code属性中获取。使用Exception类型、Response Status Code、Response Status Code Range从_errorPages中查找在web.xml文件中注册的映射,如果有找到,则使用ServletContext中的RequestDispatcher将当前的Request、Response派发的其error处理逻辑;否则使用ErrorHandler中的逻辑。

ResourceHandler

ResourceHandler直接继承自AbstractHandler,用于处理静态资源以及If-Modified-Since头。使用PathInfo以及注册的或ContextHandler中的BaseResource作为Base查找Resource,如果找不到并且请求的类型是/jetty-stylesheet.css资源,则查找注册的或默认的stylesheet资源;如果查找到的资源是目录,如果URL不是以"/"结尾,则重定向到"URL/",否则查找是否有welcome list中配置的页面存在以显示,否则列出文件列表或者显示403 Forbidden页面;对If-Modified-Since请求头,如果资源存在LastModified属性,并且比请求中设置的值要小或相等(以秒为单位),返回304 Not Modified;根据文件名或PathInfo以及注册的MineTypes信息设置ContentType,设置Content-Length、Cache-Control、Last-Modified等响应头,将Resource内容写入Response中。

顺便提及:Resource是Jetty中对静态资源的抽象,其子类有URLResource、FileResource、JarResource、JarFileResource、BadResource等。类似Spring中对Resource抽象,不详述。

AbstractHandlerContainer

AbstractHandlerContainer继承自AbstractHandler,并实现了HandlerContainer接口。HandlerContainer接口定义如下:
public interface HandlerContainer extends LifeCycle {
    // 返回当前Handler包含的所有Handler
    public Handler[] getHandlers();
    // 返回当前Handler和其所有子Handler包含的所有Handler
    public Handler[] getChildHandlers();
    // 返回所有当前Handler和其所有子Handler包含的所有Handler中类型为指定类型的Handler
    public Handler[] getChildHandlersByClass(Class<?> byclass);
    // 返回第一个所有当前Handler和其所有子Handler包含的所有Handler中类型为指定类型的Handler
    public <T extends Handler> T getChildHandlerByClass(Class<T> byclass);
}
AbstractHandlerContainer主要实现了两个方法:
// 将所有当前handler或其子handler中类型为byClass的Handler添加到list中,并返回该list实例
protected Object expandHandler(Handler handler, Object list, Class<Handler> byClass);
// 从root的HandlerContainer中找到handler所在的HandlerContainer实例,并且该HandlerContainer必须属于type类型
public static <T extends HandlerContainer> T findContainerOf(HandlerContainer root,Class<T>type, Handler handler);

HandlerCollection

HandlerCollection继承自AbstractHandlerContainer,它使用Handler数组作为容器来存储Handler,并且可已配置是否在启动后还能修改这个容器,以及启动是是否并行启动:
    private final boolean _mutableWhenRunning;
    private volatile Handler[] _handlers;
    private boolean _parallelStart=false
在handle()方法实现中,遍历数组中所有的Handler,调用其handle()方法。
在setHandlers()和setServer()方法实现中,需要生成并分发handler的Relationship发生变化的事件给在Server中的Container中注册的Listener,以及更新相应Handler中对Server的引用。

HandlerList

它继承自HandlerCollection,只是重写了handle()方法的逻辑,即在HandlerList中,它遍历整个Handlers 数组直到有异常发生或baseRequest的isHandled()返回true(什么时候baseRequest的handled属性会被设置为true呢?在发送请求之前或相应状态码被设置);而HandlerCollection则会遍历整个Handlers数组直到一个RuntimeException发生或IOException发生或整个Handler数组遍历完成,如果中途有出现其他异常最后统一抛出。

ContextHandlerCollection

ContextHandlerCollection继承自HandlerCollection,使用PathMap存储请求URI到ContextHandler的映射。

HotSwapHandler

HotSwapHandler继承自AbstractHandlerContainer,支持动态的替换内部的Handler(即在设置Handler时,如果当前Handler已经启动,则并立即启动新设置的Handler,并停止原来的Handler)。它使用Composite模式,内部只是使用一个Handler来保存一个集合的Handler,因而如果要注册多个Handler,则这个Handler的类型需要HandlerContainer。

HandlerWrapper

HandlerWrapper继承自AbstractHandlerContainer,它类似Composite模式,使用一个Handler本身来表达一个HandlerContainer,因而同HotSwapHandler,它只是包含一个Handler字段用与表示、存储Handler集合,并且其实现也和HotSwapHandler类似,所不同的是它不会动态的启动新设置的Handler,即它只是一个Handler的Wrapper。 

ConnectHandler

ConnectHandler继承自HandlerWrapper,它实现了一个代理服务器。

DebugHandler

DebugHandler继承自HandlerWrapper,用于测试时使用,在logs 目录中yyyy_mm_dd.debug.log文件的形式纪录请求的时间和URL以及响应的时间和响应状态码,并设置线程名为请求URL。

IPAccessHandler

IPAccessHandler继承自HandlerWrapper,用于添加可以使用或需要组织的IP列表,并返回403 Forbidden响应。

RequestLogHandler

RequestLogHandler继承自HandlerWrapper,在所有handler处理结束后,将Request和Response使用RequestLog类打印到日志中。

StatisticsHandler

StatisticsHandler继承自HandlerWrapper,用于纪录一些统计信息,如请求数、请求时间、dispatched数与时间、suspended数、resume数、expire数、1xx到5xx的响应数、响应总的字节数等。