Http11InputBuffer service () method to parse the Request line and Request header, and completed the org. Apache. Coyote. Preliminary encapsulates the Request object.

Further encapsulation of Request

org.apache.catalina.connector.Request

Http11Processor->service():
    getAdapter().service(request, response);
CoyoteAdapter->service():
    ......
    postParseSuccess = postParseRequest(req, request, res, response);
Copy the code

The req is called getAdapter (). The service () method to get the object, the request of the fully qualified called org. Apache. Catalina. The request, It exists to org. Apache. Coyote. Request a reference, it implements it interface, it inherits the ServletRequest, initial state, There is no Request object in the Notes property of req. It is newly generated and can be used directly next time. The same is true for the generation of response.

CoyoteAdapter->postParseRequest(): ...... connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData()); .Copy the code

PostParseRequest () continues to org. Apache. Coyote. Some attribute assignment Request, here will make further analysis. For example, a request URL with; name=value; Name2 =value2, that’s the argument; In the URL request, special characters are passed in %xx encoding. These special characters are escaped, for example, %20 is escaped as a space; Escape the double slash // to a single slash/and so on. What follows is a process of parsing the Cookie information in the request header and assigning the sessionId.

org.apache.catalina.connector.RequestFacade

Although org. Apache. Catalina. Connector. Request the existence of org. Apache. Coyote. Request a reference, but its getRequest () method returns the isn’t it

Request->getRequest():
    if (facade == null) {
        facade = new RequestFacade(this);
    }
    if (applicationRequest == null) {
        applicationRequest = facade;
    }
    return applicationRequest;
Copy the code

The actual request class in the business logic is the RequestFacade, and the facade pattern is used primarily for data security reasons. Multiple components in the system are involved in data interaction. If a component does not want to expose all its internal data to its components, it can use facade mode to expose only part of the data and complete data access through this mode.

The RequestFacade has a reference to the Request, and the operations on the facade are the same as those on the Request.

Route mapper

Mapper->map():
    internalMap(host.getCharChunk(), uri.getCharChunk(), version, mappingData);
Copy the code

GetMapper () returns the Mapper class. The Mapper class has a host member variable of type MappedHost. Spring Boot only has a reference to the host container named Loacalhost by default. Use the default host if you can’t find it, so either type localhost or 127.0.0.1 to find the default host (see Mapper->internalMap for source code).

Host class has a contextList member variable, which is MappedContext array type of contexts member variables, the content is a web application, spring boot default only a container for the content of reference, The string startsWith(“”) method always returns true, so whatever URL you type, you find the default content (see Mapper->internalMap for the source code).

The Content class has a versions member of the ContextVersion array type. Spring Boot has only one ContextVersion by default. Assume the following matches the default wrapper (see Mapper->internalMapWrapper for the source code). Specific as follows:

  • An exact match
  • Prefix matching
  • The suffix match
  • Resource matching
    • Exact resource matching
    • Resource prefix Matching
    • Resource suffix Matching
  • The default matching

If the URL is xxxx.jsp, then the wrapper with extensionWrappers script 0 is matched

After the match is complete, you can use getMappingData(), getHost(), getContext(), and getWrapper() to view the match result.

The pipe

CoyoteAdapter->service():
    connector.getService().getContainer().getPipeline().getFirst().invoke(
        request, response);
Copy the code

GetContainer () returns Engine, the global Engine container whose standard implementation is StandardEngine.

GetPipeline () returns a Pipeline, which is a pipe that connects multiple objects. Its standard implementation is StandardPipeline. Each Pipeline has two valves, first and BASIC. Basic is also known as the basic Valve. Valve refers to the class that implements Valve interface, getFirst(), return first if first has it, otherwise return BASIC.

In the invoke() method, the function of each valve is described in the following order:

StandardEngineValve

Gets the Host Host object corresponding to the request and calls the first valve of the pipe in the Host object.

ErrorReportValve

Output the error in HTML format.

StandardHostValve

Gets the Context object corresponding to the request and calls the first valve of the pipe in the Context object.

AuthenticatorBase

Permission authentication is implemented internally by Tomcat in a few scenarios

StandardContextValve

First determine whether the forbidden directory WEB-INF or meta-INF is accessed, get the Wrapper object corresponding to the request, and call the first valve of the pipe in the Wrapper object

StandardWrapperValve

Count the number of requests, count the processing time, allocate the Servlet memory, execute the Servlet filter, call the service method of the Servlet, and release the Servlet memory

StandardWrapperValve->invoke():
    filterChain.doFilter
        (request.getRequest(), response.getResponse());
Copy the code

Appendix multithreading and Http11Processor

The Http11Processor handles the task. It has only one request member variable and is defined in the class. If an Http11Processor processes multiple requests at the same time, it is not thread-safe. This raises the question of whether the HttpServletRequest used by different requests is the same object.

I wrote a demo

@RequestMapping("/test/**") public String test2(HttpServletRequest request) throws InterruptedException { log.info("{}",  request.hashCode()); TimeUnit.SECONDS.sleep(5); return "test**"; }Copy the code

The Http11Processor has a cache mechanism for processing a request, and the corresponding Http11Processor will generate the request when it is insufficient.

To do this, find where the Http11Processor is generated, AbstractProtocol->ConnectionHandler->process():Processor Processor = connections.get(socket); Connections is a ConcurrentHashMap set that is created when the processor is empty and put into the map.

The key is the socket, which is an object reference to NioChannel, from the wrapper, which is a member variable of SocketProcessorBase. Find where SocketProcessorBase was generated, ProcessSocket (SocketWrapperBase socketWrapper, SocketEvent Event, Boolean dispatch); SocketWrapper is the parameter passed in.

SocketWrapper is attachment, It is generated where NioEndpoint->Poller->run():NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment(); PollerEvent-> Run (), socketWrapper is a member of PollerEvent. NioEndpoint->Poller-> Register (), where socket, Wrapper, and pollerEvent reside. Socket is an object reference to NioChannel.

At this point, the argument conjecture, the way to review the previous content.