preface

Mention the framework, you have to mention to see the source code, we usually always want to ask god with us to fly, but look at the source code is one of the most direct way to learn from god, but every time we summon up the courage to see the source code is such





But a little bit of open source, and suddenly a flood of code, your heart may be like this





So I don’t be afraid to look at the source code before, a map to get Mybatis Mapper principle also mentioned,Mybatis source code is relatively simple, relatively suitable for just began to overcome the fear of looking at the source code combat, because Struts2 shortly before and spread security problems, so Java development, performance layer framework base This is SpringMVC, so we will tear, pull, pull off the mysterious coat of SpringMVC, can be compared to the previous fear, Struts2 implementation process is not that difficult, this article will cover some of the Struts2, JavaWeb and SpringMVC use you some details.





SpringMVC execution flowchart. PNG

This is one of the most classic SpringMVC execution flow chart, I believe do Java development have seen, which has three core places, respectively is HandlerMapping, HandlerAdapter, HttpMessageConveter. After reading this picture and having a big picture view, it is time to start. The high energy ahead, please hold firmly and sit well.





Look at the source code, first to find the entrance, so where is the entrance? As you can see from the flowchart, the DispatcherServlet is the gateway core class (as can be seen from the SpringMVC configuration file), but with so many methods in it, we know which method is the gateway? Let’s start by looking at the inheritance diagram of the DispatcherServlet





Inheritance. PNG

Void init(ServletConfig config) void init(ServletConfig config) void init(ServletConfig config service(ServletRequest req, ServletResponse res (), void destroy(), and service () are not included in the DispatcherServlet. Super.service (request, response); super.service(request, response); The corresponding method (doGet or doPost) will be called depending on the type of request obtained. For example, this test is a GET request, so doGet will be called.





doGet.png





processRequest.png





doService.png

DoDispatch, literally, is a method that distributes requests, and the core logic is there





doDispatch.png

The checkMultipart method checks for binary requests (file upload requests).

    protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        //multipartResolver is a view resolver, and request is a binary request
        if (this.multipartResolver ! =null && this.multipartResolver.isMultipart(request)) {
            if(WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) ! =null) {
                logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
                        "this typically results from an additional MultipartFilter in web.xml");
            }
            else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {
                logger.debug("Multipart resolution failed for current request before - " +
                        "skipping re-resolution for undisturbed error rendering");
            }
            else {
                / / if is binary, the request packing layer and returns the MultipartHttpServletRequest
                return this.multipartResolver.resolveMultipart(request); }}// If not returned before: return original request.
        return request;
    }Copy the code

Because it is not a binary request, the original object is returned, so multipartRequestParsed = (processedRequest! = request); The result is false

MappedHandler = getHandler(processedRequest);





getHandler.png

We know from the word HandlerExecutionChain that this is the chain of processing execution

HandlerMapping

HandlerMapping is a request processing mapper, which can select the most appropriate handle(controller written by itself) according to different requests. Multiple request processing mapper can be configured, and who matches who executes first.

So this for… What is it traversing? This is already configured in the DispatcherServlet file





handlerMapping.png

In fact, this is packaging different Mapping to determine whether it is configured by BeanNameUrl or Annotation. What is BeanNameUrl? This is what we normally configure in an XML file

<bean name="/hello" class="Permission name"></bean>Copy the code

And with that, you pass the request in and you get the HandlerExecutionChain

HandlerExecutionChain handler = hm.getHandler(request);Copy the code

HandlerExecutionChain

The HandlerExecutionChain consists of two parts, one is the controller corresponding to the request and the other is the interceptor. Before the handle is actually executed, a series of operations, such as data conversion, formatting, and data validation, are performed by the interceptor

Also, if you have n interceptors, HandlerExecutionChain will have n+1 interceptors, one of which is internal, so we know the order of execution. For example, the interceptor is executed before the controller is executed, so this thing is called the processing execution chain

HandlerAdapter ha = getHandlerAdapter(mappedHandler.gethandler ());





getHandlerAdapter.png

HandlerAdapter

The HandlerAdapter is used to execute the handler(controller), and the for… What exactly is in traversing? In fact, this is also configured in the configuration file





HandlerAdapter.png

Here is the judge handle compatible or not this RequestMappingHandleAdapter, suitable for return

if (ha.supports(handler)) {
    return ha;
}Copy the code

And then you go down

String method = request.getMethod();Copy the code

This method gets the method type, so what’s the difference between a GET and a POST request? Get requests have a cache, but POST requests do not

And then you go down

if(! mappedHandler.applyPreHandle(processedRequest, response)) {return;
}Copy the code




applyPreHandle.png

Here we can recall the three methods of the HandlerInterceptor

public class MyInterceptor implements HandlerInterceptor {

    // Represents the method called before the controller method executes, and returns Boolean, true, pass, false, intercept
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("MyInterceptor.preHandle");
        return true;
    }

    // After the controller executes the method, the view merges before
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor.postHandle");
    }

    // The view is combined with the method called after completion
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("MyInterceptor.afterCompletion"); }}Copy the code

The interceptor is primarily traversed here, and if false is returned, the interceptor starts from! MappedHandler. ApplyPreHandle (processedRequest, response this judgment can be learned, no longer continue to perform.

Keep going down

// Actually invoke the handler.
mv = ha.handle(processedRequest, response,mappedHandler.getHandler());Copy the code

This method does a lot of things. For example, the parameter automatic injection mentioned earlier is done in this step. This step is too deep and limited to discuss for the moment

@RequestMapping("/test")
public String test(Model model) {
    model.addAttribute("msg"."Hello Toby");
    return "hello";
}Copy the code

And then you go further down

// Default view name
applyDefaultViewName(request, mv);Copy the code

What does this default view name do? Have we ever run into a situation where we return Model without View, for example

@RequestMapping("/value2")
public User value2(a) {
    Circular View path [value2]: would dispatch back to the current Handler URL [/value2] again
    // SpringMVC will give you the view by default. The default view name is: request name (/value2)
    // request /value2 again
    return new User("toby"."24");
}Copy the code

Continue to go down mappedHandler. ApplyPostHandle (processedRequest, response, mv);





applyPostHandle.png

From here we know that the order of execution is the other way around.

Keep going down

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);Copy the code




processDispatchResult.png





render.png

// This determines whether to forward or redirect, or change to another view
view.render(mv.getModelInternal(), request, response);Copy the code




render.png





renderMergedOutputModel.png

This method is used to pass in the request path

protected请求转发;分派请求getRequestDispatcher(HttpServletRequest request, String path) {
    return request.getRequestDispatcher(path);
}Copy the code

Get the RequestDispatcher object and then call the forward, which is actually the bottom of the servlet

rd.forward(request, response);Copy the code

Keep going down

mappedHandler.triggerAfterCompletion(request, response, null);Copy the code




triggerAfterCompletion.png

Now, the sequence of interceptor execution is defined by applyPreHandle, applyPostHandle, triggerAfterCompletion, and the following diagram





Flowchart of interceptor execution. PNG

Write in the end

This is the end of SpringMVC’s simple implementation flow, but the essence of SpringMVC’s design is not just what we’ve just seen. Every detail is worth thinking about, but the process of thinking is where the value of looking at the source code comes in. For a simple example, take asynchronous callbacks. IOS usually uses blocks, Android interfaces, and JavaScript functions. What are the similarities and differences between them And how do we solve the problem of asynchronous to synchronous? What do we do on iOS? These are all worth thinking about.

Time is relatively short, if there is wrong place in the article, we hope to correct.

If you like my article, you are welcome to give a thumbs up to Jian Shu and pay attention to Fei Chao. We will share the front and back end of the article for a long time