Objective
The context container is a representative of a Web project that primarily manages the servlet instances, where the servlet instances appear as wrapper. Now the question is how can we find the detailed servlet through the context container? Before you solve the problem. The context container needs to be started, and the process of starting is to load the class resource files and open the sub-containers as well as the pipeline pipeline. After you start the context container. will be able to handle the detailed request, detailed through the request object, from the code listing 4-3 Wrapper wrapper = request.getWrapper()
can be seen.
So what happens when the context invokes the Invoke method? The Org.apache.catalina.core.StandardContextValve invoke method is run in detail. Equivalent to enter the context pipeline, to start through the pipeline in a gate.
The standardcontext process can be simplified with the following diagrams:
Code Listing 4-3:
/** * Select the appropriate child Wrapper to process this request, * based on the specified request URI. If No matching Wrapper can * is found, return an appropriate HTTP error. * * @param request request to being processed * @param response response to being produced * * @exception IOException if an Inpu T/output Error occurred * @exception servletexception if a servlet error occurred */@Overridepublic final void Invoke (Requ EST request, Response Response) throws IOException, servletexception {//Disallow any direct access to resources UN Der Web-inf or meta-inf messagebytes requestpathmb = REQUEST.GETREQUESTPATHMB (); if ((Requestpathmb.startswithignorecase ("/meta-inf/", 0)) | | (Requestpathmb.equalsignorecase ("/meta-inf")) | | (Requestpathmb.startswithignorecase ("/web-inf/", 0)) | | (Requestpathmb.equalsignorecase ("/web-inf"))) {Response.senderror (httpservletresponse.sc_not_found); Return }//Select the Wrapper to is used for This Request Wrapper Wrapper = Request.getwrapper (); if (wrapper = = NULL | | wrapper.isunavailable ()) {response.senderror (httpservletresponse.sc_not_found); Return }//Acknowledge the request try {response.sendacknowledgement (); } catch (IOException IoE) {Container.getlogger (). Error (Sm.getstring ("Standardcontextvalve.acknowle Dgeexception "), IoE); Request.setattribute (Requestdispatcher.error_exception, IoE); Response.senderror (Httpservletresponse.sc_internal_server_error); Return } if (request.isasyncsupported ()) {request.setasyncsupported (Wrapper.getpipeline (). isasyncsupported ()); } wrapper.getpipeline (). GetFirst (). Invoke (request, response);}
- No direct access to resources under Web-inf or Meta-inf folders
- Select a detailed wrapper processing request
- Returns a confirmation response
- Call the wrapper container's Invoke method, handing the processing request to standardwrappervalve processing
Wrapper Container
The wrapper container is responsible for managing a servlet that contains the servlet's load, initialization, and resource collection. Wrapper is the lowest-level container, which cannot be added to a sub-container. Wrapper is an interface. Its standard implementation class is Standardwrapper, the following is the structure of these two classes:
The above diagram is only part of the class. Because wrapper is closely related to Servlets. The Loadservlet method is responsible for loading the servlet with its source code such as the following:
Code Listing 4-4:
/** * Load and initialize an instance of the this servlet, if there are not already * at least one initialized instance. This can is used, for example, to * load servlets that is marked in the deployment descriptor to being loaded * at Server St Artup time. */public synchronized Servlet Loadservlet () throws Servletexception {if (unloading) {throw new Servletexceptio N (sm.getstring ("Standardwrapper.unloading", GetName ())); }//Nothing to do if we already has an instance or an instance pool if (!singlethreadmodel && (instance! = NULL)) return instance; PrintStream out = System.out; if (swallowoutput) {systemloghandler.startcapture (); } servlet servlet; try {long t1=system.currenttimemillis (); complain if no servlet class has been specified if (Servletclass = = null) {unavailable (null); throw new Servletexception (sm.getstring ("Standardwrapper.notclass", GetnaMe ())); } Instancemanager Instancemanager = ((Standardcontext) getParent ()). Getinstancemanager (); try {servlet = (servlet) instancemanager.newinstance (Servletclass); } catch (ClassCastException e) {unavailable (null); Restore the context ClassLoader throw new Servletexception (Sm.getstring ("Standardwrapper.not Servlet ", Servletclass), E); } catch (Throwable e) {e = Exceptionutils.unwrapinvocationtargetexception (e); Exceptionutils.handlethrowable (e); unavailable (null); Added Extra log statement for Bugzilla 36630://http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if (log.isdebugenabled ()) {Log.debug (sm.getstring ("Standardwrapper.instantiate", Servletclass), E); }//Restore The context ClassLoader throw new Servletexception (sm.getst Ring ("StandardwrappeR.instantiate ", Servletclass), E); } if (multipartconfigelement = = null) {Multipartconfig annotation = Servlet.getclass (). Getannotation (Multipartconfig.class); if (annotation! = null) {multipartconfigelement = new Multipartconfigelement (Annota tion); }} processservletsecurityannotation (Servlet.getclass ()); Special handling for Containerservlet instances if (servlet instanceof Containerservlet) && (Iscontainerprovidedservlet (servletclass) | | (Context) getParent ()). Getprivileged ()) {((Containerservlet) servlet). Setwrapper (this); } classloadtime= (int) (System.currenttimemillis ()-t1); if (servlet instanceof Singlethreadmodel) {if (Instancepool = = null) {Instancepool = new Stack <Servlet> (); } Singlethreadmodel = true; }//init servlet Instance Initservlet (servlet); Firecontainerevent ("Load", this); Loadtime=system.currenttimemillis ()-t1; } finally {if (swallowoutput) {String log = Systemloghandler.stopcapture (); if (log! = null && log.length () > 0) {if (getservletcontext () = null) {get ServletContext (). log (log); } else {out.println (log); }}}} return servlet;}
This class is primarily responsible for initializing a servlet instance, invoking the instance's Init method, and then notifying the event listener of interest. Code Listing 4-3 calls the wrapper invoke method, what is the completion of this method?
Code Listing 4-5:
/** * Invoke The servlet We is managing, respecting the rules regarding * servlet lifecycle and Singlethreadmodel support . * * @param request request to being processed * @param response response to being produced * * @exception IOException if an Inpu T/output Error occurred * @exception servletexception if a servlet error occurred */@Overridepublic final void Invoke (Requ EST request, Response Response) throws IOException, servletexception {//Initialize local variables we may need Boolean unavailable = false; Throwable throwable = null; This should is a Request attribute long T1=system.currenttimemillis (); requestcount++; Standardwrapper wrapper = (standardwrapper) getcontainer (); Servlet servlet = null; Context context = (context) wrapper.getparent (); Check for the application being marked unavailable if (!context.getstate (). IsAvailable ()) {Response.senderro R (httpservletresponse.sc_service_unavailable, Sm.getstring ("Standardcontext.isunavailable")); unavailable = true; }//Check for the servlet being marked unavailable if (!unavailable && wrapper.isunavailable ()) {Co Ntainer.getlogger (). info (sm.getstring ("Standardwrapper.isunavailable", Wrapper.getname ())); Long available = wrapper.getavailable (); if ((Available > 0L) && (Available < Long.max_value)) {Response.setdateheader ("Retry-after", Ava ilable); Response.senderror (httpservletresponse.sc_service_unavailable, sm.getstring ("Standardwrapper.isunavaila Ble ", Wrapper.getname ())); } else if (available = = Long.max_value) {response.senderror (Httpservletresponse.sc_not_found, Sm.getstring ("Standardwrapper.notfound", Wrapper.getname ())); } unavailable = true; }//Allocate a servlet instance to process this request try { if (!unavailable) {servlet = Wrapper.allocate (); }} catch (Unavailableexception e) {Container.getlogger (). Error (Sm.getstring ("Standardwrapper.a Llocateexception ", Wrapper.getname ()), e); Long available = wrapper.getavailable (); if ((Available > 0L) && (Available < Long.max_value)) {Response.setdateheader ("Retry-after", Ava ilable); Response.senderror (httpservletresponse.sc_service_unavailable, sm.getstring ("Standardwrapper.isunava Ilable ", Wrapper.getname ())); } else if (available = = Long.max_value) {response.senderror (Httpservletresponse.sc_not_found, Sm.getstring ("Standardwrapper.notfound", Wrapper.getname ())); }} catch (Servletexception e) {Container.getlogger (). Error (Sm.getstring ("Standardwrapper.allocateexception", Wrapper.getname ()), Standardwrapper.getrootcause (e)); Throwable = e; Exception (request, response, E); } catch (Throwable e) {exceptionutils.handlethrowable (e); Container.getlogger (). Error (Sm.getstring ("Standardwrapper.allocateexception", Wrapper.getname ()), e); Throwable = e; Exception (request, response, E); servlet = null; }//Identify If the request is a Comet related now, the servlet has been allocated Boolean Comet = false; if (servlet instanceof cometprocessor && request.getattribute (globals.comet_supported_attr) = = Boolean . true) {Comet = true; Request.setcomet (TRUE); } messagebytes REQUESTPATHMB = REQUEST.GETREQUESTPATHMB (); Dispatchertype dispatchertype = dispatchertype.request; if (Request.getdispatchertype () ==dispatchertype.async) Dispatchertype = Dispatchertype.async; Request.setattribute (globals.dispatcher_tYpe_attr,dispatchertype); Request.setattribute (globals.dispatcher_request_path_attr, REQUESTPATHMB); Create the filter chain for this request applicationfilterfactory factory = Applicationfilterfactory.getinsta NCE (); 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 {if ( Servlet! = null) && (Filterchain! = null)) {//Swallow output if needed if (Context.getswal Lowoutput ()) {try {systemloghandler.startcapture (); if (request.isasyncdispatching ()) {//todo Servlet3-async (asynccontextim PL) Request.getasynccontext ()). Dointernaldispatch (); } else if (comeT) {filterchain.dofilterevent (request.getevent ()); Request.setcomet (TRUE); } else {Filterchain.dofilter (Request.getrequest (), Response.getres Ponse ()); }} finally {String log = Systemloghandler.stopcapture (); if (log! = null && log.length () > 0) {context.getlogger (). info (log); }}} and else {if (request.isasyncdispatching ()) {//todo SERV Let3-async ((Asynccontextimpl) Request.getasynccontext ()). Dointernaldispatch (); } else if (Comet) {Request.setcomet (true); Filterchain.dofilterevent (Request.getevent ()); } else {Filterchain.dofilter (Request.getrequest (), Response.getresponse ()); }}}} catch (Clientabortexception e) {throwable = e; Exception (request, response, E); } catch (IOException e) {Container.getlogger (). Error (Sm.getstring ("Standardwrapper.serviceexceptio N ", Wrapper.getname (), Context.getname ()), e); Throwable = e; Exception (request, response, E); } catch (Unavailableexception e) {Container.getlogger (). Error (Sm.getstring ("Standardwrapper.servic Eexception ", Wrapper.getname (), Context.getname ()), e); Throwable = e; Exception (request, response, E); Wrapper.unavailable (e); Long available = wrapper.getavailable (); if ((Available > 0L) && (Available < Long.max_value)) {Response.setdateheader ("Retry-after", Ava ilable); Response.senderror (Httpservletresponse.sc_service_unavailable, Sm.getstring ("Standardwrapper.isunavailable", Wrapper.getname ())); } else if (available = = Long.max_value) {response.senderror (Httpservletresponse.sc_not_found, Sm.getstring ("Standardwrapper.notfound", Wrapper.getname ())); }//Do not save exception in ' Throwable ', because we//does not want to do exception (request, Response, E) p Rocessing} catch (Servletexception e) {throwable rootcause = Standardwrapper.getrootcause (e); if (! ( Rootcause instanceof clientabortexception) {Container.getlogger (). Error (Sm.getstring ("STA Ndardwrapper.serviceexceptionroot ", Wrapper.getname (), Context.getname (), E.getmessage ()), Rootcause); } throwable = e; Exception (request, response, E); } catch (Throwable e) {exceptionutils.handlethrowable (e); Container.getlogger (). Error (Sm.getstring ("Standardwrapper.serviceexception", Wrapper.getname (), Context.getname ()), e); Throwable = e; Exception (request, response, E); }//Release the filter chain (if any) for this request if (filterchain! = null) {if (Request.iscomet ()) { If This is a Comet request and then the same chain'll be used for the//processing of all Subseque NT events. Filterchain.reuse (); } else {filterchain.release (); }}//deallocate The allocated servlet instance try {if (servlet! = null) {Wrapper.deallocat E (servlet); }} catch (Throwable e) {exceptionutils.handlethrowable (e); Container.getlogger (). Error (Sm.getstring ("Standardwrapper.deallocateexception", Wrapper.getname ()) , e); if (Throwable = = null) {throwable = e; Exception (Request, Response, E); }}//If This servlet had been marked permanently unavailable,//unload it and release this instance try { if (servlet = null) && (wrapper.getavailable () = = Long.max_value)) {Wrapper.unload ( ); }} catch (Throwable e) {exceptionutils.handlethrowable (e); Container.getlogger (). Error (Sm.getstring ("Standardwrapper.unloadexception", Wrapper.getname ()), E) ; if (Throwable = = null) {throwable = e; Exception (request, response, E); } }}
- Initialize some local variables
- Infers whether the current app is available. is to infer whether the project is actually
- Assigning a servlet instance
- Create a filter chain for the request
- Filter Filter Request
- Close Filter
- Delegating the original delegated servlet instance again
- Freeing resources
This method is related to the above loadservlet relationship such as the following:
It can be seen that the Invoke method of Standardwrappervalve is called when the allocate method of Loadservlet is called, and after the wrapper container gets the request, Using the Allocate method, a servlet instance is popped from the instance pool stack to handle the request, and the servlet instance is encapsulated as a Filterchain object, followed by a series of filter filters to reach the Servlet.service () method. This process can be as follows:
Deep understanding of the five Tomcat series: Context Containers and wrapper containers