生活随笔
收集整理的這篇文章主要介紹了
tomcat架构分析(valve源码导读)【转】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原文地址:https://www.iteye.com/blog/gearever-1540028
源碼面前,了無秘密?
???????????????????????????? ----侯捷?
在tomcat架構分析(valve機制)(http://gearever.iteye.com/blog/1536022)里已經對valve的機制做了分析?,F(xiàn)在通過源碼來加深下理解。侯捷說過,源碼面前,了無秘密。通過這些代碼,可以看到在tomcat中我們經常碰到的一些現(xiàn)象或配置是怎么實現(xiàn)的。?
StandardEngineValve?
看一下StandardEngineValve的調用邏輯;?
Java代碼??
public?final?void?invoke(Request?request,?Response?response)??????throws?IOException,?ServletException?{????????????Host?host?=?request.getHost();??????if?(host?==?null)?{??????????......??????????return;??????}????????????host.getPipeline().getFirst().invoke(request,?response);????}??
可以清晰的看到,根據(jù)request定位到可以處理的host對象,同時,開始從頭調用host里的pipeline上的valve。?
StandardHostValve?
看一下StandardHostValve的調用邏輯;?
Java代碼??
public?final?void?invoke(Request?request,?Response?response)??????throws?IOException,?ServletException?{????????????Context?context?=?request.getContext();??????if?(context?==?null)?{??????????......??????????return;??????}????????......????????????context.getPipeline().getFirst().invoke(request,?response);????????????if?(Globals.STRICT_SERVLET_COMPLIANCE)?{??????????request.getSession(false);??????}????????????response.setSuspended(false);????????????Throwable?t?=?(Throwable)?request.getAttribute(Globals.EXCEPTION_ATTR);????????if?(t?!=?null)?{??????????throwable(request,?response,?t);??????}?else?{??????????status(request,?response);??????}????????????Thread.currentThread().setContextClassLoader??????????(StandardHostValve.class.getClassLoader());????}??
可以清晰的看到,注釋部分里根據(jù)request定位到可以處理的context對象,同時,開始從頭調用context里的pipeline上的valve。在調用完context的所有的valve之后(當然也是context調用完其對應的wrapper上的所有valve之后),藍色部分顯示了拿到response對象時可以做的處理。?
熟悉tomcat的可能有配置錯誤信息的經驗,例如;?
Xml代碼??
<error-page>????<error-code>404</error-code>????<location>/error.jsp</location>???</error-page>??
它就是為了在用戶訪問資源出現(xiàn)HTTP 404錯誤時,將訪問重定向到一個統(tǒng)一的錯誤頁面。這樣做一是為了美觀,另一個主要作用是不會將一些具體的錯誤信息例如java拋異常時的棧信息暴露給用戶,主要還是出于安全的考慮。 上述代碼中的注釋部分就是實現(xiàn)這個重定向功能。?
StandardContextValve?
看一下StandardContextValve的調用邏輯;其代碼比較多,只貼一些比較核心的吧。?
Java代碼??
public?final?void?invoke(Request?request,?Response?response)??????throws?IOException,?ServletException?{????????......????????????Wrapper?wrapper?=?request.getWrapper();??????if?(wrapper?==?null)?{??????????notFound(response);??????????return;??????}?else?if?(wrapper.isUnavailable())?{??????????......??????}????????????????Object?instances[]?=?context.getApplicationEventListeners();????????ServletRequestEvent?event?=?null;????????????......??????????wrapper.getPipeline().getFirst().invoke(request,?response);?????????????......???????????????}??
可以清晰的看到,注釋部分里根據(jù)request定位到可以處理的wrapper對象,同時,開始從頭調用wrapper里的pipeline上的valve。 需要注意的是,這里在調用wrapper的valve前后,分別有響應request初始化及撤銷事件的邏輯,tomcat有一整套事件觸發(fā)體系,這里限于篇幅就不闡述了。有時間專門說。?
StandardWrapperValve?
看一下StandardWrapperValve的調用邏輯;其代碼比較多,只貼一些比較核心的吧;?
Java代碼??
public?final?void?invoke(Request?request,?Response?response)??????throws?IOException,?ServletException?{????????????......??????requestCount++;??????????StandardWrapper?wrapper?=?(StandardWrapper)?getContainer();??????Servlet?servlet?=?null;??????Context?context?=?(Context)?wrapper.getParent();????????????......????????????try?{??????????if?(!unavailable)?{??????????????????????????servlet?=?wrapper.allocate();??????????????????????????}??????}?catch?(UnavailableException?e)?{??????????......??????}???????......??????????ApplicationFilterFactory?factory?=??????????ApplicationFilterFactory.getInstance();??????ApplicationFilterChain?filterChain?=??????????factory.createFilterChain(request,?wrapper,?servlet);??????????request.setComet(false);????????????????try?{??????????String?jspFile?=?wrapper.getJspFile();??????????if?(jspFile?!=?null)??????????????request.setAttribute(Globals.JSP_FILE_ATTR,?jspFile);??????????else??????????????request.removeAttribute(Globals.JSP_FILE_ATTR);??????????if?((servlet?!=?null)?&&?(filterChain?!=?null))?{??????????????????????????if?(context.getSwallowOutput())?{??????????????????try?{??????????????????????SystemLogHandler.startCapture();??????????????????????if?(comet)?{??????????????????????????filterChain.doFilterEvent(request.getEvent());??????????????????????????request.setComet(true);??????????????????????}?else?{??????????????????????????????????????????????????filterChain.doFilter(request.getRequest(),???????????????????????????????????response.getResponse());??????????????????????}??????????????????}?finally?{??????????????????????String?log?=?SystemLogHandler.stopCapture();??????????????????????if?(log?!=?null?&&?log.length()?>?0)?{??????????????????????????context.getLogger().info(log);??????????????????????}??????????????????}??????????????}?else?{??????????????????if?(comet)?{??????????????????????request.setComet(true);??????????????????????filterChain.doFilterEvent(request.getEvent());??????????????????}?else?{??????????????????????????????????????????filterChain.doFilter??????????????????????????(request.getRequest(),?response.getResponse());??????????????????}??????????????}????????????}??????????request.removeAttribute(Globals.JSP_FILE_ATTR);??????}?catch?(ClientAbortException?e)?{??????????request.removeAttribute(Globals.JSP_FILE_ATTR);??????????throwable?=?e;??????????exception(request,?response,?e);??????}???????......??}??
可以清晰的看到,注釋部分里,先是能拿到相應的wrapper對象;然后完成加載wrapper對象中的servlet,例如如果是jsp,將完成jsp編譯,然后加載servlet等;再然后,根據(jù)配置生成一個filter棧,通過執(zhí)行棧,調用完所有的filter之后,就調用servlet,如果沒有配置filter,就直接調用servlet,生成filter棧是通過request的URL模式匹配及servlet名稱來實現(xiàn)的,具體涉及的東西在tomcat的servlet規(guī)范實現(xiàn)中再闡述吧。?
以上,完成了一整套servlet調用的過程。通過上面的闡述,可以看見valve是個很靈活的機制,通過它可以實現(xiàn)很大的擴展。?
Valve的應用及定制化?
Tomcat除了提供上面提到的幾個標準的valve實現(xiàn)外,也提供了一些用于調試程序的valve的實現(xiàn)。實現(xiàn)valve需要繼承org.apache.catalina.valves.ValveBase基類。 以RequestDumperValve為例,?
引用 org.apache.catalina.valves.RequestDumperValve
RequestDumperValve是打印出request及response信息的valve。其實現(xiàn)方法為:?
Java代碼??
public?void?invoke(Request?request,?Response?response)???????????????????throws?IOException,?ServletException?{?????????????Log?log?=?container.getLogger();?????????????????????log.info("REQUEST?URI?="?+?request.getRequestURI());???????????......???????????log.info("?queryString="?+?request.getQueryString());???????????......???????????log.info("-------------------------------------------------------");?????????????????????????????getNext().invoke(request,?response);?????????????????????????????log.info("-------------------------------------------------------");???????????......???????????log.info("?contentType="?+?response.getContentType());???????????Cookie?rcookies[]?=?response.getCookies();???????????for?(int?i?=?0;?i?<?rcookies.length;?i++)?{???????????????log.info("?cookie="?+?rcookies[i].getName()?+?"="?+???????????????????rcookies[i].getValue()?+?";?domain="?+???????????????????rcookies[i].getDomain()?+?";?path="?+?rcookies[i].getPath());???????????}???????????String?rhnames[]?=?response.getHeaderNames();???????????for?(int?i?=?0;?i?<?rhnames.length;?i++)?{???????????????String?rhvalues[]?=?response.getHeaderValues(rhnames[i]);???????????????for?(int?j?=?0;?j?<?rhvalues.length;?j++)???????????????log.info("?header="?+?rhnames[i]?+?"="?+?rhvalues[j]);????????????????????}??????????log.info("?message="?+?response.getMessage());???????????log.info("========================================================");?????}??
可以很清晰的看出,它打印出了request及response的信息,其中紅色部分顯示它調用valve鏈表中的下一個valve。我們可以這樣配置它;?
Xml代碼??
<Host?name="localhost"??appBase="webapps"??????????????unpackWARs="true"?autoDeploy="true"??????????????xmlValidation="false"?xmlNamespaceAware="false">????????<Valve?className="org.apache.catalina.valves.RequestDumperValve"/>????????<Context?path="/my"?docBase="?/usr/local/tomcat/backup/my"?>????????????????????</Context>????????<Context?path="/my2"?docBase="?/usr/local/tomcat/backup/my"?>???????????????????</Context>??</Host>??
這樣,只要訪問此host下的所有context,都會打印出調試信息。 Valve的應用有很多,例如cluster,SSO等,會有專門一章來講講。
轉載于:https://www.cnblogs.com/davidwang456/articles/11452742.html
總結
以上是生活随笔為你收集整理的tomcat架构分析(valve源码导读)【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。