Deep understanding of the five Tomcat series: Context Containers and wrapper containers

Source: Internet
Author: User
Tags event listener

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);}
    1. No direct access to resources under Web-inf or Meta-inf folders
    2. Select a detailed wrapper processing request
    3. Returns a confirmation response
    4. 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); }    }}
    1. Initialize some local variables
    2. Infers whether the current app is available. is to infer whether the project is actually
    3. Assigning a servlet instance
    4. Create a filter chain for the request
    5. Filter Filter Request
    6. Close Filter
    7. Delegating the original delegated servlet instance again
    8. 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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.