天天看點

深入Jetty源碼之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();

}

深入Jetty源碼之Handler總述

abstracthandler繼承自aggregatelifecycle并實作了handler接口,是基本上所有handler的基類。它的實作也非常簡單,它定義了server成員,并實作了getserver和setserver方法,在setserver實作中,如果已存在的server引用和新設定的server不同,則先将自身從已存在的server的container中移除,然後将自身添加到新的server的container中,并更新内部對server的引用執行個體。在destroy方法中,也會将自身從server引用執行個體的container中移除。

defaulthandler直接繼承自abstracthandler,它可以用于handler連結清單的末尾handler,用于處理所有不能被其他handler處理的請求:/favicon.ico -> 顯示jetty圖示,/ -> 顯示404錯誤頁面,并列出所有可用的contextpath,任何其他請求顯示404錯誤頁面。圖示的顯示和可用contextpath的清單顯示都是可配的。

dumphandler直接繼承自abstracthandler,用于測試和調試,顯示request消息内容。它顯示的資訊有pathinfo、contenttype、characterencoding、requestline、headers、parameters、cookiename、cookies、attributes、content等。

errorhandler直接繼承自abstracthandler,用于處理錯誤頁面,使用contexthandler.seterrorhandler()或server.addbean()注冊。它顯示出錯代碼、原因以及更詳細的資訊。其中異常棧從request的javax.servlet.errro.exception中擷取。

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直接繼承自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中。

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繼承自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的引用。

它繼承自handlercollection,隻是重寫了handle()方法的邏輯,即在handlerlist中,它周遊整個handlers 數組直到有異常發生或baserequest的ishandled()傳回true(什麼時候baserequest的handled屬性會被設定為true呢?在發送請求之前或相應狀态碼被設定);而handlercollection則會周遊整個handlers數組直到一個runtimeexception發生或ioexception發生或整個handler數組周遊完成,如果中途有出現其他異常最後統一抛出。

contexthandlercollection繼承自handlercollection,使用pathmap存儲請求uri到contexthandler的映射。

hotswaphandler繼承自abstracthandlercontainer,支援動态的替換内部的handler(即在設定handler時,如果目前handler已經啟動,則并立即啟動新設定的handler,并停止原來的handler)。它使用composite模式,内部隻是使用一個handler來儲存一個集合的handler,因而如果要注冊多個handler,則這個handler的類型需要handlercontainer。

handlerwrapper繼承自abstracthandlercontainer,它類似composite模式,使用一個handler本身來表達一個handlercontainer,因而同hotswaphandler,它隻是包含一個handler字段用與表示、存儲handler集合,并且其實作也和hotswaphandler類似,所不同的是它不會動态的啟動新設定的handler,即它隻是一個handler的wrapper。 

connecthandler繼承自handlerwrapper,它實作了一個代理伺服器。

debughandler繼承自handlerwrapper,用于測試時使用,在logs 目錄中yyyy_mm_dd.debug.log檔案的形式紀錄請求的時間和url以及響應的時間和響應狀态碼,并設定線程名為請求url。

ipaccesshandler繼承自handlerwrapper,用于添加可以使用或需要組織的ip清單,并傳回403 forbidden響應。

requestloghandler繼承自handlerwrapper,在所有handler處理結束後,将request和response使用requestlog類列印到日志中。

statisticshandler繼承自handlerwrapper,用于紀錄一些統計資訊,如請求數、請求時間、dispatched數與時間、suspended數、resume數、expire數、1xx到5xx的響應數、響應總的位元組數等。