日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tomcat架构分析(valve源码导读)【转】

發(fā)布時間:2025/4/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tomcat架构分析(valve源码导读)【转】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文地址:https://www.iteye.com/blog/gearever-1540028

源碼面前,了無秘密?
???????????????????????????? ----侯捷?
在tomcat架構(gòu)分析(valve機(jī)制)(http://gearever.iteye.com/blog/1536022)里已經(jīng)對valve的機(jī)制做了分析?,F(xiàn)在通過源碼來加深下理解。侯捷說過,源碼面前,了無秘密。通過這些代碼,可以看到在tomcat中我們經(jīng)常碰到的一些現(xiàn)象或配置是怎么實(shí)現(xiàn)的。?
StandardEngineValve?
看一下StandardEngineValve的調(diào)用邏輯;?

Java代碼??
  • public?final?void?invoke(Request?request,?Response?response)??
  • ????throws?IOException,?ServletException?{??
  • ??
  • ????//?定位host??
  • ????Host?host?=?request.getHost();??
  • ????if?(host?==?null)?{??
  • ????????......??
  • ????????return;??
  • ????}??
  • ??
  • ????//?調(diào)用host的第一個valve??
  • ????host.getPipeline().getFirst().invoke(request,?response);??
  • ??
  • }??

  • 可以清晰的看到,根據(jù)request定位到可以處理的host對象,同時,開始從頭調(diào)用host里的pipeline上的valve。?
    StandardHostValve?
    看一下StandardHostValve的調(diào)用邏輯;?

    Java代碼??
  • public?final?void?invoke(Request?request,?Response?response)??
  • ????throws?IOException,?ServletException?{??
  • ??
  • ????//?定位context??
  • ????Context?context?=?request.getContext();??
  • ????if?(context?==?null)?{??
  • ????????......??
  • ????????return;??
  • ????}??
  • ??
  • ????......??
  • ??
  • ????//?調(diào)用context的第一個valve??
  • ????context.getPipeline().getFirst().invoke(request,?response);??
  • ??
  • ????//?更新session??
  • ????if?(Globals.STRICT_SERVLET_COMPLIANCE)?{??
  • ????????request.getSession(false);??
  • ????}??
  • ??
  • ????//?Error?page?processing??
  • ????response.setSuspended(false);??
  • ??
  • ????//如果有拋異?;蚰硞€HTTP錯誤,導(dǎo)向響應(yīng)的配置頁面??
  • ????Throwable?t?=?(Throwable)?request.getAttribute(Globals.EXCEPTION_ATTR);??
  • ??
  • ????if?(t?!=?null)?{??
  • ????????throwable(request,?response,?t);??
  • ????}?else?{??
  • ????????status(request,?response);??
  • ????}??
  • ??
  • ????//?Restore?the?context?classloader??
  • ????Thread.currentThread().setContextClassLoader??
  • ????????(StandardHostValve.class.getClassLoader());??
  • ??
  • }??

  • 可以清晰的看到,注釋部分里根據(jù)request定位到可以處理的context對象,同時,開始從頭調(diào)用context里的pipeline上的valve。在調(diào)用完context的所有的valve之后(當(dāng)然也是context調(diào)用完其對應(yīng)的wrapper上的所有valve之后),藍(lán)色部分顯示了拿到response對象時可以做的處理。?
    熟悉tomcat的可能有配置錯誤信息的經(jīng)驗(yàn),例如;?

    Xml代碼??
  • <error-page>??
  • ??<error-code>404</error-code>??
  • ??<location>/error.jsp</location>??
  • ?</error-page>??

  • 它就是為了在用戶訪問資源出現(xiàn)HTTP 404錯誤時,將訪問重定向到一個統(tǒng)一的錯誤頁面。這樣做一是為了美觀,另一個主要作用是不會將一些具體的錯誤信息例如java拋異常時的棧信息暴露給用戶,主要還是出于安全的考慮。 上述代碼中的注釋部分就是實(shí)現(xiàn)這個重定向功能。?

    StandardContextValve?
    看一下StandardContextValve的調(diào)用邏輯;其代碼比較多,只貼一些比較核心的吧。?

    Java代碼??
  • public?final?void?invoke(Request?request,?Response?response)??
  • ????throws?IOException,?ServletException?{??
  • ??
  • ????......??
  • ??
  • ????//?定位wrapper??
  • ????Wrapper?wrapper?=?request.getWrapper();??
  • ????if?(wrapper?==?null)?{??
  • ????????notFound(response);??
  • ????????return;??
  • ????}?else?if?(wrapper.isUnavailable())?{??
  • ????????......??
  • ????}??
  • ??
  • ????//?Normal?request?processing??
  • ????//web.xml中配置web-app/listener/listener-class??
  • ????Object?instances[]?=?context.getApplicationEventListeners();??
  • ??
  • ????ServletRequestEvent?event?=?null;??
  • ??
  • ????//響應(yīng)request初始化事件,具體的響應(yīng)listener是可配置的???
  • ????......??
  • ????//調(diào)用wrapper的第一個valve??
  • ????wrapper.getPipeline().getFirst().invoke(request,?response);???
  • ??
  • ????//響應(yīng)request撤銷事件,具體的響應(yīng)listener是可配置的???
  • ????......???????????????
  • }??

  • 可以清晰的看到,注釋部分里根據(jù)request定位到可以處理的wrapper對象,同時,開始從頭調(diào)用wrapper里的pipeline上的valve。 需要注意的是,這里在調(diào)用wrapper的valve前后,分別有響應(yīng)request初始化及撤銷事件的邏輯,tomcat有一整套事件觸發(fā)體系,這里限于篇幅就不闡述了。有時間專門說。?
    StandardWrapperValve?
    看一下StandardWrapperValve的調(diào)用邏輯;其代碼比較多,只貼一些比較核心的吧;?

    Java代碼??
  • public?final?void?invoke(Request?request,?Response?response)??
  • ????throws?IOException,?ServletException?{??
  • ??????
  • ????......??
  • ????requestCount++;??
  • ????//定位wrapper??
  • ????StandardWrapper?wrapper?=?(StandardWrapper)?getContainer();??
  • ????Servlet?servlet?=?null;??
  • ????Context?context?=?(Context)?wrapper.getParent();??
  • ??????
  • ????......??
  • ??
  • ????//?Allocate?a?servlet?instance?to?process?this?request??
  • ????try?{??
  • ????????if?(!unavailable)?{??
  • ????????????//加載servlet??
  • ????????????servlet?=?wrapper.allocate();??????????????????
  • ????????}??
  • ????}?catch?(UnavailableException?e)?{??
  • ????????......??
  • ????}???
  • ????......??
  • ????//?根據(jù)配置建立一個filter-servlet的處理鏈表,servlet在鏈表的尾端??
  • ????ApplicationFilterFactory?factory?=??
  • ????????ApplicationFilterFactory.getInstance();??
  • ????ApplicationFilterChain?filterChain?=??
  • ????????factory.createFilterChain(request,?wrapper,?servlet);??
  • ????//?Reset?comet?flag?value?after?creating?the?filter?chain??
  • ????request.setComet(false);??
  • ??
  • ????//?Call?the?filter?chain?for?this?request??
  • ????//?NOTE:?This?also?calls?the?servlet's?service()?method??
  • ????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))?{??
  • ????????????//?Swallow?output?if?needed??
  • ????????????if?(context.getSwallowOutput())?{??
  • ????????????????try?{??
  • ????????????????????SystemLogHandler.startCapture();??
  • ????????????????????if?(comet)?{??
  • ????????????????????????filterChain.doFilterEvent(request.getEvent());??
  • ????????????????????????request.setComet(true);??
  • ????????????????????}?else?{??
  • ????????????????????????//調(diào)用filter-servlet鏈表??
  • ????????????????????????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?{??
  • ????????????????????//調(diào)用filter-servlet鏈表??
  • ????????????????????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);??
  • ????}???
  • ????......??
  • }??

  • 可以清晰的看到,注釋部分里,先是能拿到相應(yīng)的wrapper對象;然后完成加載wrapper對象中的servlet,例如如果是jsp,將完成jsp編譯,然后加載servlet等;再然后,根據(jù)配置生成一個filter棧,通過執(zhí)行棧,調(diào)用完所有的filter之后,就調(diào)用servlet,如果沒有配置filter,就直接調(diào)用servlet,生成filter棧是通過request的URL模式匹配及servlet名稱來實(shí)現(xiàn)的,具體涉及的東西在tomcat的servlet規(guī)范實(shí)現(xiàn)中再闡述吧。?
    以上,完成了一整套servlet調(diào)用的過程。通過上面的闡述,可以看見valve是個很靈活的機(jī)制,通過它可以實(shí)現(xiàn)很大的擴(kuò)展。?
    Valve的應(yīng)用及定制化?
    Tomcat除了提供上面提到的幾個標(biāo)準(zhǔn)的valve實(shí)現(xiàn)外,也提供了一些用于調(diào)試程序的valve的實(shí)現(xiàn)。實(shí)現(xiàn)valve需要繼承org.apache.catalina.valves.ValveBase基類。 以RequestDumperValve為例,?

    引用 org.apache.catalina.valves.RequestDumperValve


    RequestDumperValve是打印出request及response信息的valve。其實(shí)現(xiàn)方法為:?

    Java代碼??
  • public?void?invoke(Request?request,?Response?response)???
  • ????????????????throws?IOException,?ServletException?{???
  • ??
  • ????????Log?log?=?container.getLogger();???
  • ??
  • ????????//?Log?pre-service?information???
  • ????????log.info("REQUEST?URI?="?+?request.getRequestURI());???
  • ????????......???
  • ????????log.info("?queryString="?+?request.getQueryString());???
  • ????????......???
  • ????????log.info("-------------------------------------------------------");???
  • ??????????
  • ????????//?調(diào)用下一個valve??
  • ????????getNext().invoke(request,?response);???
  • ??????????
  • ????????//?Log?post-service?information???
  • ????????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的信息,其中紅色部分顯示它調(diào)用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,都會打印出調(diào)試信息。 Valve的應(yīng)用有很多,例如cluster,SSO等,會有專門一章來講講。

    轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/11452742.html

    總結(jié)

    以上是生活随笔為你收集整理的tomcat架构分析(valve源码导读)【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。