Tomcat basic and Operation

The basic architecture

Tomcat It consists of two modules collaboration

  • connector
  • container

connector Responsible for parsing  HTTP the request, for example  请求头 ,  查询字符串 ,   and the like. Generation   and later handed over   , which is responsible for calling the appropriate   .请求参数HttpRequestHttpResponse 
containerServlet

Connector

Tomcat The default  Connector is  HttpConnector . As  Connector we must implement  Connector this interface.

Tomcat It will open later start a thread , do an infinite loop by  ServerSocket waiting for a request. Once the request is generated  Socket , note that there  HttpConnector will not handle their own  Socket , but give it to  HttpProcessor . Details see below the code , here I only kept the key code.

public void run() {
        // Loop until we receive a shutdown command
        while (!stopped) {
            Socket socket = null;
            try {
                socket = serverSocket.accept(); //等待链接
            } catch (AccessControlException ace) {
                log("socket accept security exception", ace);
                continue;
            }
            // Hand this socket off to an appropriate processor
            HttpProcessor processor = createProcessor();
            processor.assign(socket);  //这里是立刻返回的
            // The processor will recycle itself when it finishes
        }
    }

 

 

Note that the above  processor.assign(socket); should be returned immediately and does not block there, waiting. Because Tomcat can not only handle one request, it is asynchronous, each  processor process is a separate thread.

HttpProcessor

The above code does not call the show  HttpProcessor the  process way, that this method is how to call it? Let's look at  HttpProcessorthe  run method.

public void run() {
        // Process requests until we receive a shutdown signal
        while (!stopped) {
            // Wait for the next socket to be assigned
            Socket socket = await(); 
            if (socket == null)
                continue;
            // Process the request from this socket
            try {
                process(socket);
            } catch (Throwable t) {
                log("process.invoke", t);
            }
            // Finish up this request
            connector.recycle(this);
        }
    }

 

 

We found him to call  await a method to block waiting to get  socket method. And before  Connector calling  assign allocated, what is the reason?

Below a closer look  await and  assign approach. These two methods collaboration, when  assign acquired  socket when will be notified  await and then return  socket .

 

synchronized void assign(Socket socket) {
    // Wait for the Processor to get the previous Socket
    while (available) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    // Store the newly available Socket and notify our thread
    this.socket = socket;
    available = true;
    notifyAll();
}
private synchronized Socket await() {
    // Wait for the Connector to provide a new Socket
    while (!available) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    // Notify the Connector that we have received this Socket
    Socket socket = this.socket;
    available = false;
    notifyAll();
    return (socket);
}

 

 

The default  available is  false .

Then there is left to do is resolve the request, filling  HttpRequest and  HttpResponse objects, and then to  container be responsible.

Here I go into details, but more how to parse

 

private void process(Socket socket) {
    //parse
    ....
    connector.getContainer().invoke(request, response);
    ....
}

 

 

Container

A Container is an object that can execute requests received from a client, and return responses based on those requests

 

Container It is an interface that this class implements the interface instance can be received processing request, the corresponding call  Servlet .

There are four categories  Container , four  Container parallel relationship between not, but the father-son relationship

  • Engine - the top-most container, may comprise a plurality of Host
  • Host - represents a virtual host can contain multiple Context
  • Context - on behalf of a  web应用 , that is  ServletContext , it can contain multiple Wrappers
  • Wrapper - a representative of  Servlet , can not contain other container, which is the lowest level

Container calls

Is like a container processing plant, processing acceptance  request , processing and pipelining is very similar, but a little different. Here will be used is called a  thing, Chinese translation is   ,   to put in order the pipeline processing, the machining tool is called   , is like a scalpel,   you can add more   , finishing tool called Pipeline管道requestValvePipelineValveBaseValve

The above list may speak more abstract, let's look at the code. Engine The top container, so the above  invoke , is performed by  Engine the method. StandardEngine It is  Engine the default implementation, note that it also implements  Pipeline an interface, and contains  Pipeline .

Its construction method is also specified  baseValve , which is the last call of the pipeline Valve

public StandardEngine() {
    super();
    pipeline.setBasic(new StandardEngineValve());
}

 

 

Well, then we see  invoke that this method is inherited from  ContainerBase . Only one line, to between  pipeline , for processing.

public void invoke(Request request, Response response)
        throws IOException, ServletException {
        pipeline.invoke(request, response);
}

 

 

Here is  StandardPipeline the  invoke realization, which is the default  pipeline implementation.

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);
}

 

 

Only one line! Call  StandardPipelineValveContext the  invokeNext method, which is an  pipeline internal class. Let us look

Specific code

 

public void invokeNext(Request request, Response response)
            throws IOException, ServletException {
            int subscript = stage;
            stage = stage + 1;
            // Invoke the requested Valve for the current request thread
            if (subscript < valves.length) {
                valves[subscript].invoke(request, response, this);  //加工
            } else if ((subscript == valves.length) && (basic != null)) {
                basic.invoke(request, response, this);
            } else {
                throw new ServletException
                    (sm.getString("standardPipeline.noValve"));
            }
}

 

 

It calls  pipeline used  Valve to to  request do the processing, when Valve executed, will call  BaseValve , which is above StandardEngineValve ,

We look at its  invoke methods

 

// Select the Host to be used for this Request
StandardEngine engine = (StandardEngine) getContainer();
Host host = (Host) engine.map(request, true);
if (host == null) {
    ((HttpServletResponse) response.getResponse()).sendError
        (HttpServletResponse.SC_BAD_REQUEST,
            sm.getString("standardEngine.noHost",
                        request.getRequest().getServerName()));
    return;
}
// Ask this Host to process this request
host.invoke(request, response);

 

 

It is through  (Host) engine.map(request, true); the corresponding acquired  Host , and then proceeds to the next layer of containers to continue. Later execution order

And  Engine the same, but many go I

 

Summary execution order

After a long series of  invoke last execution order of the first layer of the finished container. I guess you see a little dizzy, summary of what I have here.

Connector -> HttpProcessor.process() -> StandardEngine.invoke() -> StandardPipeline.invoke() ->

StandardPipelineValveContext.invokeNext() -> valves.invoke() -> StandardEngineValve.invoke() ->

StandardHost.invoke()

 

 

Here to position  Engine this layer end. Next were  Host , exactly the same steps

StandardHost.invoke() -> StandardPipeline.invoke() ->

StandardPipelineValveContext.invokeNext() -> valves.invoke() -> StandardHostValve.invoke() ->

StandardContext.invoke()

 

 

And then to  Context this layer processing, select a corresponding to the last  Wrapping executed.

Wrapper

Wrapper Equivalent to a  Servlet example,  StandardContext will be more in accordance with the  request selected corresponding to the  Wrapper call. We take a look directly

Wrapper Of  basevalve it is if you call  Servlet the  service method. Here is  StandardWrapperValve the  invoke way I omitted a lot,

Look at the key.

 

public void invoke(Request request, Response response,
                       ValveContext valveContext)
        throws IOException, ServletException {
        // Allocate a servlet instance to process this request
        if (!unavailable) {
            servlet = wrapper.allocate();
        }
        // Create the filter chain for this request
        ApplicationFilterChain filterChain =
            createFilterChain(request, servlet);
        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        String jspFile = wrapper.getJspFile();  //是否是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);
        }
        sreq.removeAttribute(Globals.JSP_FILE_ATTR);
    }

 

 

First call  wrapper.allocate() , this method is very important, it will pass  反射 to find the corresponding  servlet the  class file structure of an example of a return to us. Then create a  FilterChain familiar  j2ee of you should be no stranger to this? This is what we in the development of web app  the use of time  filter . Then on the implementation of  doFilter the method, and it will call  internalDoFilter , we look at this method

private void internalDoFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        // Call the next filter if there is one
        if (this.iterator.hasNext()) {
            ApplicationFilterConfig filterConfig =
              (ApplicationFilterConfig) iterator.next();
            Filter filter = null;
            
            filter = filterConfig.getFilter();
            filter.doFilter(request, response, this);
            return;
        }
        // We fell off the end of the chain -- call the servlet instance
        if ((request instanceof HttpServletRequest) &&
            (response instanceof HttpServletResponse)) {
            servlet.service((HttpServletRequest) request,
                            (HttpServletResponse) response);
        } else {
            servlet.service(request, response);
        }
}

 

 

Finally, this approach saw the  service method, now you know in the use of  filter time if you do not perform  doFilter ,  service the reason will not be executed by the handle.

Guess you like

Origin blog.csdn.net/anwarkanji/article/details/90528238
Recommended