Tomcat source code analysis (4) -- responsible link mode for container processing

Source: Internet
Author: User

Objective: In this article, I want to understand connector. getContainer (). invoke (request, response); how does one pass the invoke of the container to servlet or jsp?
StandardEngine does not have the invoke method. It inherits from ContainerBase (in fact, all containers are inherited from ContainerBase and there are some common methods and attributes of containers in the ContainerBase class). The invoke method of the abstract class ContainerBase is as follows:
[Java]
Protected Pipeline pipeline = new StandardPipeline (this); // The implementation of standard pipelines StandardPipeline
Public void invoke (Request request, Response response)
Throws IOException, ServletException {
Pipeline. invoke (request, response); // call the invoke in the pipeline
}

The Code shows that the invoke method of ContainerBase is passed to Pipeline, and the invoke method of Pipeline is called. The Pipeline class is a Pipeline class. Each Pipeline class Pipeline contains several Valve classes. The Valve class implements the Valve interface class, and the Valve interface declares the invoke method. The concept of pipelines and valves is very similar to the filter mechanism in servlet programming. pipelines are like filter chains, and valves are like filters. However, there is also a basic valve concept in the pipeline. The so-called basic valve is called in the pipeline after all the general valves are called. Both common valves and basic valves implement the Value interface and inherit from the abstract class ValveBase. In tomcat, when the pipeline's invoke method is called, the pipeline will call the valve's invoke method in sequence. First, let's take a look at the invoke method of the pipeline StandardPipeline:
[Java]
Public void invoke (Request request, Response response)
Throws IOException, ServletException {
// Invoke the first Valve in this pipeline for this request
(New StandardPipelineValveContext (). invokeNext (request, response );
}

StandardPipelineValveContext is an internal class in the pipeline. The internal class is used to help the pipeline call the invoke method of the valve Value in sequence. The following describes its definition code:
[Java]
Protected class StandardPipelineValveContext
Implements ValveContext {
Protected int stage = 0;
Public String getInfo (){
Return info;
}
Public void invokeNext (Request request, Response response)
Throws IOException, ServletException {
Int subscript = stage; // The access variable of the valve
Stage = stage + 1; // The number of valves currently accessed
// Invoke the requested Valve for the current request thread
If (subscript <valves. length ){
Valves [subscript]. invoke (request, response, this); // array of valves for the pipeline
} Else if (subscript = valves. length) & (basic! = Null )){
Basic. invoke (request, response, this); // after the basic valve is called, The invoke valve of the basic valve of the pipeline is called.
} Else {
Throw new ServletException
(Sm. getString ("standardPipeline. noValve "));
}
}
}
The invokeNext method of the internal class StandardPipelineValveContext accesses the next pipeline array by using local variables. The variable stage of the pipeline class stores the currently accessed valves and valves stores all valves of the pipeline, when the invoke method of the common valve is called, the internal class StandardPipelineValveContext is passed in, so that the invokeNext method can be called in the common valve to access the invoke method of the next valve, the following describes the invoke method of a common valve:
[Java]
Public void invoke (Request request, Response response, ValveContext valveContext)
Throws IOException, ServletException {
// Pass this request on to the next valve in our pipeline
ValveContext. invokeNext (request, response); // call the invoke method of the next Valve
System. out. println ("Client IP Logger Valve ");
ServletRequest sreq = request. getRequest ();
System. out. println (sreq. getRemoteAddr ());
System. out. println ("------------------------------------");
}
The invoke method of this valve is used to call the invokeNext method of the next valve by transmitting the invokeNext method of StandardPipelineValveContext (implementing the ValveContext interface. Then, the requested IP address is printed.
Finally, let's look at the invokeNext method of StandardPipelineValveContext. after calling the valves valve of the general valve array, we start to call the basic invoke method. Here we first talk about the initialization of the basic valve, the base valve has been initialized for each constructor class of the container. Check the constructor of the container StandardEngine:
[Java]
Public StandardEngine (){
Super ();
Pipeline. setBasic (new StandardEngineValve (); // The basic valve StandardEngine of the container StandardEngineValve
}
That is, when the container is constructed, the basic valve has been added to the pipeline, so that the invokeNext method in StandardPipelineValveContext can call the basic valve invoke. invoke (request, response, this); enter the basic valve StandardEngineValve, check the basic valve StandardEngineValve invoke method:
[Java]
Public void invoke (Request request, Response response,
ValveContext valveContext)
Throws IOException, ServletException {
...........................
 
// Ask this Host to process this request
Host. invoke (request, response );
 
}

Many codes are omitted here, mainly to better understand the call logic. In StandardEngine's basic valve StandardEngineValve, the sub-container invoke method is called (the Sub-container is StandardHost ), remember to start ctor. invoke (request, response) (that is, the invoke method of StandardEngine) is now passed smoothly to the invoke method of the sub-container StandardHost, Which is changed to StandardHost. invoke (request, response ). From this we can guess that StandardHost will also pass it to its sub-container, and finally pass it to the invoke method of StandardWrapper, and then call the invoke method of StandardWrapperValue of the basic Valve of StandardWrapper, since StandardWrapper is the smallest container and cannot be passed to the invoke method of other containers, what does the invoke method do? There are two main tasks: 1. Create a filter chain and 2. Allocate a servlet or jsp. The main code is as follows:
[Java]
Invoke method of StandardWrapperValue
Servlet = wrapper. allocate (); // allocate a servlet
........................................ ............................
// Create the filter chain for this request
ApplicationFilterChain filterChain =
CreateFilterChain (request, servlet );
........................................ .................
String jspFile = wrapper. getJspFile (); // allocate a jsp
If (jspFile! = Null)
Sreq. setAttribute (Globals. JSP_FILE_ATTR, jspFile );
Else
Sreq. removeAttribute (Globals. JSP_FILE_ATTR );
If (servlet! = Null) & (filterChain! = Null )){
FilterChain. doFilter (sreq, sres); // call the filter chain to process requests. sreq and sres are the request and response packaging classes, where servlet services methods are called.
}

Here we will not focus on jsp, but on servlet, through servlet = wrapper. allocate (); enters the allocate method of StandardWrapper. allocate mainly calls the loadServlet method. In the loadServlet method class, a servlet object is instantiated using the tomcat class loader, the init and service methods of the servlet are called: www.2cto.com.
[Java]
StandardWrapper's loadServlet method (many other code is omitted here)
Servlet servlet = null;
String actualClass = servletClass; // servlet bytecode String
Loader loader = getLoader ();
ClassLoader classLoader = loader. getClassLoader (); // get the Class loader
Class classClass = null;
If (classLoader! = Null ){
System. out. println ("Using classLoader. loadClass ");
ClassClass = classLoader. loadClass (actualClass); // instantiate the servlet through the Class Loader
} Else {
System. out. println ("Using forName ");
ClassClass = Class. forName (actualClass); // instantiate the servlet through reflection
}
Servlet = (Servlet) classClass. newInstance (); // instantiate the servlet
Servlet. init (facade); // call the servlet init
If (loadOnStartup> 0) & (jspFile! = Null )){
// Invoking jspInit
HttpRequestBase req = new HttpRequestBase ();
HttpResponseBase res = new HttpResponseBase ();
Req. setServletPath (jspFile );
Req. setQueryString ("jsp_precompile = true ");
Servlet. service (req, res );
}; // Call the jsp service method. jsp will be compiled into a servlet, so there will also be a service method

So far, the request has been passed to the servlet service (or jsp service) method, and the whole process of the Request ends here, and the rest is to return to the client. Several questions are raised here. 1: so many Servlets, how does tomcat know which servlet to request? This question will be discussed later in the next blog.


Author: haitao111313

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.