天天看點

深入Jetty源碼之ServletHandler

servlethandler繼承自scopedhandler,是jetty中用于存儲所有filter、filtermapping、servlet、servletmapping的地方,以及用于實作一次請求所對應的filter鍊和servlet執行流程的類。對servlet的架構實作中,它也被認為是handler鍊的末端,因而在它的dohandle()方法中沒有調用nexthandle()方法。

正如前面提到的,servlethandler是一個用于管理filter、filtermapping、servlet、servletmapping的容器,因而它需要一下成員用于存儲這些它管理的執行個體:

    private filterholder[] _filters=new filterholder[0];

    private filtermapping[] _filtermappings;

    private servletholder[] _servlets=new servletholder[0];

    private servletmapping[] _servletmappings;

    private final map<string,filterholder> _filternamemap= new hashmap<string,filterholder>();

    private list<filtermapping> _filterpathmappings;

    private multimap<string> _filternamemappings;

    private final map<string,servletholder> _servletnamemap=new hashmap<string,servletholder>();

    private pathmap _servletpathmap;

其中filtermapping包含了一個filter适用的所有url pattern、servlets、dispatchertype以及對應filterholder資訊:

    private int _dispatches=default;

    private string _filtername;

    private transient filterholder _holder;

    private string[] _pathspecs;

    private string[] _servletnames;

它有appliesto()方法用于判斷傳入的path和dispatchertype是否符包含目前filter。對于url pattern:*.do=>anything.do, /foo/poo/abc.do, /path/to/*=>/path/to, /path/to/abdc。

而servletmapping包含了servletname和其适用的所有url pattern,它的url pattern的mapping規則和filtermapping中的規則一樣:

    private string _servletname;

在管理filter和filtermapping中,可以使用filterholder、pathspec、dispatchertype向_filters數組中添加一個filterholder,并向_filtermappings數組中添加一個filtermapping執行個體;而由該方法引申出來的,可以直接傳入filter執行個體、filter類執行個體、filter類名,而由方法内部建立對應的filterholder執行個體;dispatchertype可以是一個enumset類型的dispatchertype;可以直接添加filter或filtermapping或兩個同時添加;也可以使用prependfiltermapping将新的filtermapping添加到數組前。對servlet和servletmapping管理也是類似,使用servletholder和pathspec添加_servlets數組和_servletmappings數組,并引申出servlet可以是執行個體、servlet類名、servlet類執行個體,而由内部建立servletholder執行個體;也可以單獨的添加servletholder或servletmapping執行個體。

在servlethandler中還有_filternamemap和_servletnamemap執行個體用于存儲filtername到filterholder以及servletname到servletholder的映射,它在每次_filters、_servlets數組更新時都會随着更新,并且在dostart方法中也會再更新一次;另外對filter還有_filterpathmapping用于存儲所有filtermapping的一個list,_filternamemapping用于存儲servletname到多個filtermapping的multimap,對servlet中也有_servletpathmap,包含pathspec到servletholder的pathmap,他們在每次_filtermappings、_servletmappings更新時以及dostart方法中都會被更新。而在start時也會start所有的filterholder和servletholder,對所有filterholder的start按其定義順序進行,而對servletholder的start,則按其initorder排序。

doscope方法用于準備執行環境,其實作邏輯為:如果傳入的target不是servletname(即以"/"開頭,表示它為path),則使用該target從_servletpathmap中找到對應的servletholder,并計算出目前的servletpath和pathinfo,如果時include類型的dispatch,設定request的javax.servlet.include.serlvet_path,javax.servlet.include.path_info屬性為計算出來的值,否則設定request的servletpath和pathinfo的值為計算出的值;對target為servletname,servletholder的執行個體從_servletnamemap字段中查找。然後将目前找到的servletholder作為useridentityscope設定到request中,以及設定org.eclipse.multipartconfig屬性為servletholder中的multipartconfig執行個體。在剛方法退出時,将useridentityscope、servletpath、pathinfo還原回原來的值。

dohandle方法用于真正實作執行邏輯:它首先通過target找到filterchain執行個體,對于target為path時,它周遊整個_filterpathmapping的清單,選出所有符合pathincontext的filterholder數組,以及從_filternamemappings中找出所有servletholder中存儲的servletname對應的filtermapping并且dispatchertype相符合的filtermapping數組,以及注冊的servletname為"*"的filtermapping且dispatchertype相符的filtermapping數組,合并這些數組,并一同用request、servletholder建立filterchain執行個體;對target為servletname時,隻需要查找_filternamemapping字段中的filtermapping。如果沒有filterholder執行個體,則向用戶端發送404 not found響應;否則如果filterchain執行個體不為null,調用其dofilter方法,傳入servletrequest和servletresponse參數,在filterchain的dofilter方法中它回一次周遊filter的dofilter方法,直到最後調用servletholder的handle方法;否則,直接調用servletholder的handle方法。