上文說HttpProcessor在啟動之后監(jiān)聽socket端口,如果socket端口有請求,該方法就調(diào)用方法connector.getContainer().invoke(request,response);去處理請求。接下來,我們來看看容器在整個請求處理過程中的作用。

本文介紹最重要的四個容器:
1、Engine:表示整個Catalina的servlet引擎
2、Host:表示一個擁有數(shù)個上下文的虛擬主機
3、Context:表示一個Web應(yīng)用,一個context包含一個或多個wrapper
4、warpper:表示一個獨立的servlet
這四個容器都實現(xiàn)了接口Container,所以他們都叫容器,他們之間有上下級別的關(guān)系,如圖所示
1、簡單容器
連接器管理socket監(jiān)聽,一旦頁面有對應(yīng)端口請求,那么容器就來處理。也就是上文中說的這個方法。
connector.getContainer().invoke(request,response);
我們在頁面請求servlet是這個樣子的:http://localhost:8080/Primitive。那么這個URI是如何解析的呢?
首先引入Maper接口,mapper接口和容器關(guān)聯(lián),負責具體處理我們的URI對應(yīng)的servlet類。
publicinterfaceMapper{ /** *mapper關(guān)聯(lián)的容器 */ publicContainergetContainer(); /** 設(shè)置關(guān)聯(lián)容器 */ publicvoidsetContainer(Containercontainer); /**返回mapper對應(yīng)的協(xié)議 *ReturntheprotocolforwhichthisMapperisresponsible. */ publicStringgetProtocol(); /** *設(shè)置mapper對應(yīng)的協(xié)議 */ publicvoidsetProtocol(Stringprotocol); /**返回該請求的負責容器。*/ publicContainermap(Requestrequest,booleanupdate); } 簡單的Mapper接口實現(xiàn)如下: publicclassSimpleContextMapperimplementsMapper{ /**mapper關(guān)聯(lián)容器 */ privateSimpleContextcontext=null; publicContainergetContainer(){ return(context); } publicvoidsetContainer(Containercontainer){ if(!(containerinstanceofSimpleContext)) thrownewIllegalArgumentException ("Illegaltypeofcontainer"); context=(SimpleContext)container; } publicStringgetProtocol(){ returnnull; } publicvoidsetProtocol(Stringprotocol){ } /**返回處理這個請求的子容器 */ publicContainermap(Requestrequest,booleanupdate){ //獲取URI StringcontextPath= ((HttpServletRequest)request.getRequest()).getContextPath(); StringrequestURI=((HttpRequest)request).getDecodedRequestURI(); StringrelativeURI=requestURI.substring(contextPath.length()); // Wrapperwrapper=null; StringservletPath=relativeURI; StringpathInfo=null; //從容器的servletMappings字段獲得servlet名稱。 Stringname=context.findServletMapping(relativeURI); if(name!=null) //從容器的children字段中獲得該servlet名稱對應(yīng)的Wrapper類實例 wrapper=(Wrapper)context.findChild(name); return(wrapper); } }
代碼中map方法返回了我們請求URI對應(yīng)的處理容器。簡單的處理容器主要就是處理我們請求的servlet。具體的他包含兩個方面的內(nèi)容:
1、生成servlet實例。
2、為管道添加處理邏輯。
生成servlet實例主要就是通過類加載器加載servlet類。然后實例化該servlet類并且調(diào)用init()方法執(zhí)行實例初始化過程。為管道添加邏輯就涉及到了管道和Vavle的概念。
管道其實就是一個責任鏈,為servlet初始化后添加一些處理邏輯Vavle。看代碼:
publicclassSimplePipelineimplementsPipeline{ publicSimplePipeline(Containercontainer){ setContainer(container); } //基礎(chǔ)的Valve可有可無 protectedValvebasic=null; //該Pipleline關(guān)聯(lián)的容器 protectedContainercontainer=null; //該pipeline包含的valves數(shù)組 protectedValvevalves[]=newValve[0]; //添加valve publicvoidaddValve(Valvevalve){ if(valveinstanceofContained) //為valve設(shè)置容器為當前類的容器。 ((Contained)valve).setContainer(this.container); //線程安全擴容放置新增vavles synchronized(valves){ Valveresults[]=newValve[valves.length+1]; System.arraycopy(valves,0,results,0,valves.length); results[valves.length]=valve; valves=results; } } publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ //生成內(nèi)部類SimplePipelineValveContext調(diào)用責任鏈 (newSimplePipelineValveContext()).invokeNext(request,response); } publicvoidremoveValve(Valvevalve){ } //內(nèi)部類 protectedclassSimplePipelineValveContextimplementsValveContext{ protectedintstage=0; publicStringgetInfo(){ returnnull; } //責任鏈調(diào)用 publicvoidinvokeNext(Requestrequest,Responseresponse) throwsIOException,ServletException{ intsubscript=stage; stage=stage+1; //InvoketherequestedValveforthecurrentrequestthread if(subscript<valves.length){ valves[subscript].invoke(request,response,this); } elseif((subscript==valves.length)&&(basic!=null)){ basic.invoke(request,response,this); } else{ thrownewServletException("Novalve"); } } }//endofinnerclass }
2、管道的原理。
管道其實就是一個責任鏈,他把需要處理的邏輯全部都組裝成為Vavle然后一個一個的去執(zhí)行,沒執(zhí)行一個首先是要去調(diào)下一個Vavle,如果調(diào)用到底部沒有其他了那就執(zhí)行邏輯,返回之后就繼續(xù)執(zhí)行它上面的Vavle。
代碼實現(xiàn):
從連接器過來的請求首先調(diào)用了容器的invoker()。invoker里面就是去執(zhí)行管道里面的邏輯處理。
publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ pipeline.invoke(request,response); } 管道的invoker需要調(diào)用責任鏈,那么他首先生成了內(nèi)部類,然后調(diào)用invokeNext()方法去執(zhí)行業(yè)務(wù)邏輯。 publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ //InvokethefirstValveinthispipelineforthisrequest (newSimplePipelineValveContext()).invokeNext(request,response); } protectedclassSimplePipelineValveContextimplementsValveContext{ protectedintstage=0; publicStringgetInfo(){ returnnull; } publicvoidinvokeNext(Requestrequest,Responseresponse) throwsIOException,ServletException{ intsubscript=stage; stage=stage+1; //InvoketherequestedValveforthecurrentrequestthread if(subscript<valves.length){ valves[subscript].invoke(request,response,this); } elseif((subscript==valves.length)&&(basic!=null)){ basic.invoke(request,response,this); } else{ thrownewServletException("Novalve"); } } }//endofinnerclass
本文標題:servlet解析演進(3)-容器
網(wǎng)站地址:http://chinadenli.net/article34/cgsese.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、網(wǎng)站制作、響應(yīng)式網(wǎng)站、品牌網(wǎng)站制作、全網(wǎng)營銷推廣、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)