本系列轉(zhuǎn)載自?http://blog.csdn.net/haitao111313/article/category/1179996?
目標(biāo):在這篇文章希望搞明白
connector.getContainer().invoke(request,?response);
調(diào)用容器的invoke后是怎么傳遞到 servlet或者jsp的?
? ?由上篇文章
Tomcat源碼分析(三)--連接器是如何與容器關(guān)聯(lián)的?
可知,
connector.getContainer()得到的容器應(yīng)該是
StandardEngine(其實應(yīng)該是由server.xml文件配置得到的,這里先假定是
StandardEngine
),
StandardEngine沒有invoke方法,它繼承與ContainerBase(事實上所有的容器都繼承于ContainerBase,在ContainerBase類有一些容器的公用方法和屬性),抽象類
ContainerBase
的invoke方法如下:
由代碼可知 ContainerBase 的invoke方法是傳遞到Pipeline,調(diào)用了Pipeline的invoke方法。這里要說一下Pipeline這個類,這是一個管道類,每一個管道類 Pipeline 包含數(shù)個閥類,閥類是實現(xiàn)了Valve接口的類,Valve接口聲明了invoke方法。管道和閥的概念跟servlet編程里面的過濾器機制非常像, 管道就像過濾器鏈,閥就好比是過濾器 。不過管道中還有一個基礎(chǔ)閥的概念,所謂基礎(chǔ)閥就是在管道中當(dāng)管道把所有的普通閥都調(diào)用完成后再調(diào)用的。不管是普通閥還是基礎(chǔ)閥,都實現(xiàn)了Value接口,也都繼承于抽象類ValveBase。在tomcat中,當(dāng)調(diào)用了管道的invoke方法,管道則會順序調(diào)用它里面的閥的invoke方法。先看看管道StandardPipeline的invoke方法:
其中StandardPipelineValveContext是管道里的一個內(nèi)部類,內(nèi)部類的作用是幫助管道順序調(diào)用閥Value的invoke方法,下面看它的定義代碼:
內(nèi)部類 StandardPipelineValveContext的invokeNext方法通過使用局部變量來訪問下一個管道數(shù)組,管道類的變量stage保存當(dāng)前訪問到第幾個閥,valves保存管道的所有閥, 在調(diào)用普通閥的invoke方法是,會把內(nèi)部類 StandardPipelineValveContext本身傳進去,這樣在普通閥中就能調(diào)用invokeNext方法以便訪問下一個閥的invoke方法 ,下面 看一個普通閥的invoke方法:
這個閥的invoke方法,通過傳進來到 StandardPipelineValveContext(實現(xiàn)了ValveContext接口 )的invokeNext方法來實現(xiàn)調(diào)用下一個閥的invoke方法。然后簡單的打印了請求的ip地址。
最后再看
StandardPipelineValveContext的invokeNext方法,調(diào)用完普通閥數(shù)組valves的閥后,開始調(diào)用基礎(chǔ)閥basic的
invoke方法,這里先說基礎(chǔ)閥的初始化,在每一個容器的構(gòu)造函數(shù)類就已經(jīng)初始化了基礎(chǔ)閥,看容器StandardEngine的構(gòu)造函數(shù):
這里省略了很多代碼,主要是為了更加理解調(diào)用邏輯,在StandardEngine的基礎(chǔ)閥StandardEngineValve里,調(diào)用了子容器invoke方法(這里子容器就是StandardHost), 還記得一開始connector.invoke(request, response)(即StandardEngine的invoke方法)現(xiàn)在順利的傳遞到子容器StandardHost的invoke方法,變成了StandardHost.invoke(request, response)。 由此可以猜測StandardHost也會傳遞給它的子容器,最后傳遞到最小的容器StandardWrapper的invoke方法,然后調(diào)用StandardWrapper的基礎(chǔ)閥StandardWrapperValue的invoke方法,由于StandardWrapper是最小的容器了,不能再傳遞到其他容器的invoke方法了,那它的invoke方法做了什么?主要做了兩件事, 1:創(chuàng)建一個過濾器鏈并 ?2:分配一個servlet或者jsp,主要代碼如下:
這里先不關(guān)注jsp,只關(guān)注一下servlet,通過servlet = wrapper.allocate(); 進入StandardWrapper的allocate方法,allocate主要就是調(diào)用了loadServlet方法,在loadServlet方法類用tomcat自己的類加載器實例化了一個servlet對象,并調(diào)用了該servlet的init和service方法:
至此已經(jīng)把請求傳遞到servlet的service(或者jsp的service)方法,整個處理請求到這里就結(jié)束了,剩下的就是返回客戶端了。這里提出幾個問題。 1:那么多的servlet,tomcat是怎么知道要請求到哪個servlet? 這個問題留待下篇博客再來講吧。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
