The article is hostedGitHub, you can go to GitHub to read, welcome to Star! Search wechat public code out of Offer to receive a variety of learning materials!

SpringMVC executes the process

For SpringMVC overview

Spring MVC is a successor to the Spring Framework and has been integrated into Spring Web Flow. The Spring framework provides a full-featured MVC module for building Web applications. Use Spring’s pluggable MVC architecture so that you can choose to use Spring’s Spring MVC framework or integrate with other MVC development frameworks when using Spring for WEB development.

SpringMVC performs process summarization

The SpringMVC framework is powerful, but the execution process is even better. So this time we will use a simple example to delve into the underlying execution flow of SpringMVC!

The following is the SpringMVC execution flow sketch, and I will highlight these parts in the underlying process analysis later, and their role!


SpringMVC implementation process schematic diagram (remember: this diagram is just to comb through ideas, not particularly rigorous, please understand)
Important components of SpringMVC (visual components)

Since we choose to analyze the underlying execution flow of SpringMVC, we must first analyze the important COMPONENTS of MVC that we can see on the surface. After analyzing the visual components, we can find a portal to analyze the underlying execution flow of SpringMVC, so analyzing its important components is even more important!

The important components of SpringMVC are composed of the core front-end Controller (web.xml), back-end Controller (Controller), and spring-mVC.xml configuration file.

  • Core front-end controller: As an MVC framework, the first thing to solve is how to receive requests. Therefore, MVC framework usually designs a front-end controller (entrance or starting point), and the selection is either Servlet or Filter. The front-end controller takes the lead in receiving requests. In SpringMVC, it is no exception. The selection of front-end controller is determined as Servlet (DispatcherServlet). Previously, after receiving requests, the end controller will also be responsible for the core scheduling management of SpringMVC, so it is both front-end and core.
  • Back-end Controller: The back-end Controller is Controller, which is equivalent to the Servlet defined earlier. In MVC framework, the back-end controller is also one of the essential components. Because it receives a large amount of data requested by the user, the parameter object (or Json) is stored in the domain to facilitate the page (JSP) value, or carries this data back to the page that needs to be redirected (redirect or request forward). It’s important to note that the backend controller is not a normal Servlet or BaseServlet at heart, it’s just a normal class that can have as many methods as baseservlets once did. These methods become handlers in SpringMVC (essentially the same thing). Therefore, in the implementation process of MVC mode, the back-end controller controls the jump of the page and the transfer of data, and also has a high status here.
  • Spring-mvc.xml configuration file: This configuration file configures a number of components that need to be loaded during execution, such as: Annotations scanner, annotation scanning drive, tried to the parser, static processor resources, abnormal parser, interceptors, upload the parser, and so on, if we want to use these components, you need in the configuration file into these components related configuration, after injection allocation from factories for SpringMVC loads during the execution of these components, For the purpose for which we use these components. So that’s why it’s so popular.
SpringMVC performs process profiling

Given that our entry point for performing process profiling is the core front-end controller, web.xml, we are entitled to know what is configured in that front-end controller! As follows:

Front end controller

As you can see from the figure above, what’s involved in the front controller is starting up both the SpringMVC factory and the Spring factory at the same time, having both factories running at the same time to process requests and respond to them. To explore the underlying execution process of SpringMVC, let’s start by loading the SpringMVC factory’s DispatcherServlet. First enter the DispatcherServlet and view all the methods in the source code, as shown below:

DispatcherServlet source all methods
DispatcherServlet inheritance FrameworkServlet

As shown above, I enter the DispatcherServlet. Since it is a Servlet, you must look for its Service method, which is at the heart of the Servlet. So I opened the method list of IDEA and searched for the service method, but failed. The Servlet has a doSerivce method, and the DispatcherServlet inherits the FrameworkServlet. Since the subclass does not have a service method, the parent class must have one. So I went into the FrameworkServlet and looked at the source code, as shown below:

FrameworkServlet source

I was excited to find the Service method in the parent class (FrameworkServlet), but it was premature. I knew nothing about the service method except the resolve method to get the request and the processRequest method. And then I found what the red arrow was pointing to. Super. service(request, response); What does that mean? This means that it inherits the service method that the parent class owns, so WHEN I click on the service method after the super period to look at the source code, it turns out that this class is an HttpServlet. Obviously, we have reached the end of the road to find the service method. There are two methods in there. One is the resolve method, which gets the request method. There is another method that I don’t know what it does, so I click to view the source code, as shown below:

ProcessRequest method source code

Now that we’ve seen the source code for the processRequest method, we need to find the important method. What’s an important method? A method wrapped around a try block must be an important method, so I find doService(Request, response); Method, and continue clicking to see the source of the doService method, as shown below:

doService(request, response); Methods the source code

Losing my patience, I was surprised to find that when I entered the doService method, I did not jump to any other class, but instead jumped to an empty doService() in that class. Methods. Alas, explore really is a not easy thing ah ~ I sighed. If the parent class is empty and the method is not implemented, the core logic code must be in the subclass. It’s polymorphic! So, I’ve come to the conclusion that it’s hard to find the logic of the entry code but I have to go back to the doService method in the DispatcherServlet. I knew at this point that it would be a long road of discovery. So I clicked on the doSerivce method in the DispatcherServlet I had missed, again, in the spirit of exploring the principle, as shown below:

DoService () method in DispatcherServlet

Now that I’m sure this is the beginning of exploring the underlying principles, I look for important logic in the doServie() method, so again I find a try block called doDispatch(Request, Response); (omits the previous various initializations and storage domain data). As you explore the underlying principles, you will find yourself getting closer and closer to the truth, although this is bound to be a long process of exploration, which I am willing to do. So click on the source code in the doDispatch() method, as shown below:

DoDispatch () method source code

I went into the doDispatch() method source code and realized that I was right about you. There are some important execution logic methods that are annotated. Next, we will analyze it one by one and gradually understand the implementation process of SpringMVC. Since you can’t explore the execution process without Debug, I made a breakpoint on the getHandler() line. The next step in the follow up execution flow is the getHandler() method, as shown below:

Find and return a handler object for the current request.

The breakpoint stops at this line because the name of getHandler(), as the name implies, is to get a Handler in the Controller layer. How did it get it? In the variable display box for the breakpoint, we see that handlerMappings is an array with three objects. They can handle different handlers in different ways, where we can click on the three objects and expand them one by one to see the important properties, as shown below:

0 = {RequestMappingHandlerMapping}
2 = {SimpleUrlHandlerMapping}

Pictured above, RequestMappingHandlerMapping the object recognition in our Controller @ RequestMapping each Handler annotations and annotation above the path. The SimpleUrlHandlerMapping object identifies the default Servlet created to handle static resource drivers, and the default Servlet path to handle static resources is given to /**, which identifies this path. The object in the HanderMapping, after obtaining the path annotations requested by each Handler of the Controller layer through annotation recognition, is executed on the next line, as shown in the figure below:

GetHandler method source code

The annotation will find all the handlers, all of which will be stored in handlerMappings, which will then walk through the object. The corresponding Handler is then obtained according to the respective request object and nulled to return the corresponding Handler object obtained. Further down, you’ll find something like this:

GetHandler method

Yes, you’ll see that the Handler you’re returning is an execution chain called HandlerExecutionChain. The chain of execution contains the handler object to be returned and an interceptorList collection containing two objects that are interceptors. So whether you use interceptors yourself or not (there are interceptors underneath), these interceptors and handler objects are executed in a chain (interceptors first, handler objects last). Execution follows the sequence of executing the interceptor and then returning and executing the Handler object. HandlerExecutionChain is returned, so it’s time to execute the chain! Which begs the question, who executes interceptor and handler objects in turn? The diagram below:

DoDispatch () method source code

After returning to the execution chain, continuing execution leads to this line of code, which is commented to look for a Handler adapter for the current request object. If you have studied the adapter design pattern you will probably understand it more easily, but if you have not, you will understand the following explanation. Knowing that it is looking for an adapter for the request object, we proceed and get the following information:

GetHandlerAdapter method source code

The execution flow goes to the getHandlerAdapter method, which looks familiar from a distance. Yes, it is similar to the HandlerMapping. This method looks for an adapter for its handler object based on the handler object that is currently returned. The handlerAdapters collection object stores three adapters. Yes, they come in pairs, and handler objects need to find the corresponding adapter to proceed. Once the adapter paired with the current handler object is found, that adapter is returned. The adapter returns with the following method:

DoDispatch () method source code

After the middle of this section of code, obtained the request of the request object and a series of judgment operations. Execution continues to the bottom, where there is an if judgment that the applyPreHandler method was executed, which is the method that precedes the interceptor. After executing the interceptor’s pre-method, proceed with the following code:

DoDispatch () method source code

This method shows that the HA object is the handler object at this point, indicating that the interceptor was executed before the handler object was executed, following the order of the execution chain. Continuing, we have wrapped the request parameter object and converted the Json string to the object in the response, returning an MV object. So what is an MV object? It’s actually the ModelAndView object defined above. After returning the MV object, continuing execution executes the following important execution logic:

DoDispatch () method source code

In the process of execution, the post-method of interceptor is judged and executed. The processDispatchResult(processdRequest, Response, mappdeHandler, MV, dispatchException) method is executed after executing the post-method and making a series of judgments. This method carries the request object, response object, handler object, ModelAndView object, etc., enter the source code of this method, you will find that he made a series of judgments, through the following method to render the ModelAndView object:

Render method source code

After rendering and view parsing the ModelAndView object, follow up with the method, because victory is just around the corner. The diagram below:

Render method source code

If you continue, you will see that it begins to resolve the view through the resolveViewName method. So, enter the method, as shown below:

ResolveViewName method source code

First, looking at the source code for this method, you can see that the viewResolvers View parser parses the ModelAndView object and returns a View object. Later the View object will also be rendered by a method called render, as follows:

view.render()

Visible, this View object is not simple, it executed after some time, because of my webpage jump when using the request forward, so to the following page source:

InternalResourceView source

Click on this method to see that the familiar request is forwarded. Here it reads and parses the spring-mvC.xml configuration file, concatenating the path forward:/XXX/XXX for the internal default request forwarding (which also parses the other components in the spring-mvC.xml configuration file), as shown below:

Forward requests (InternalResourceView. Java)

If it is a redirection, then it is a redirection method in the following class, as shown in the figure below:

Redirection (redirectView.java)

Then, after forwarding or redirecting to the JSP page (view layer), render the data to HTML, and render the HTML content, output to the browser and respond to display in the browser!

This SpringMVC I walked through the underlying execution process in the way of breaking point debugging. I am sure you will have a good harvest by interrupting debugging yourself!

Internal components of SpringMVC
  • HandlerMapping
  • HandlerAdapter (processor adapter)
  • ViewResolver
The default SpringMVC component is initialized to load

Above, we briefly went through the SpringMVC execution flow through Debug, but how did the internal components mentioned above come from? So, I found a method called initStrategies from DispatherServlet as follows:

InitStrategies method source code

Before executing the process, we do a series of initializations for the internal components. Here we trace back to the initHandlerMappings method to find the default configuration file for SpringMVC. Enter the initHandlerMappings method. Since we have no configuration (annotations or Bean labels), the first two cases in this method will be skipped and will go to the default case at the bottom, where the getDefaultStrategies method is called and the default configuration file is read.

InitHandlerMappings method source code
GetDefaultStrategies method source code

In the getDefaultStrategies method, there is a defaultStrategies. Let’s look at the class as shown below:

DefaultStrategies source

This is where the default configuration file is loaded. Click on the DEFAULT_STRATEGIES_PATH constant to find the default configuration file.

DEFAULT_STRATEGIES_PATH constants

So I managed to get to this configuration file, and it initialized various components. You can check it out:

DispatcherServlet. Properties configuration file