Interview classic questions SpringMVC execution process (source code interpretation analysis)

The article has been hosted on GitHub . You can check it out on GitHub. Welcome bosses to Star!
Search and follow the WeChat public account [Code out Offer] to receive various learning materials!

SpringMVC execution process

Overview of SpringMVC

Spring MVC is a follow-up product of SpringFrameWork and has been integrated into Spring Web Flow. The Spring framework provides a full-featured MVC module for building Web applications. Use Spring pluggable MVC architecture, so when using Spring for WEB development, you can choose to use Spring's Spring MVC framework or integrate other MVC development frameworks.

SpringMVC execution process summary

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

The following is a schematic diagram of the execution process of SpringMVC. I will focus on these parts in the schematic diagram and their functions in the analysis of the underlying process!


Outline diagram of SpringMVC execution process (remember: this diagram is just to sort out ideas, not particularly rigorous, please understand)
springMVC execution process
Important components of SpringMVC (visual components)

Since we have to choose to analyze the underlying execution process of Spring MVC, we must first analyze the important components of MVC that we can see on the surface. In this way, after analyzing the visual components, we can find the entrance to analyze the underlying execution process of SpringMVC, so it is even more important to analyze its important components!

The important components of SpringMVC are composed of 核心的前端控制器(web.xml), 后端控制器(Controller)and spring-mvc.xml配置文件.

  • The core front controller: As an MVC framework, the first thing to solve is how to receive requests. Therefore, most MVC frameworks design a front-end controller (entry or starting point), which is selected in either Servlet or Filter. The front-end controller will take the lead to work and receive requests. In SpringMVC, the selection of the front controller is determined to be Servlet (DispatcherServlet). After receiving the request, this front controller is also responsible for the core scheduling management of SpringMVC, so it is both the front end and the core.
  • Back-end controller: The back-end controller is Controller, which is equivalent to the previously defined Servlet. In the MVC framework, the back-end controller is also one of the indispensable important 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 the data back to the page that needs to be redirected (redirected or requested forwarding). It’s worth noting here that the back-end controller is not an ordinary Servlet, nor is it BaseServlet. It is just an ordinary class, but it can have many methods like BaseServlet. These methods become one by one in SpringMVC. Handler (changing soup without changing medicine, the essence remains). Therefore, in the execution process of the MVC mode, the back-end controller controls the page jump and data transmission, and it also has a high position here.
  • spring-mvc.xml configuration file: This configuration file configures many components that need to be loaded during execution, such as: annotation scanner, annotation scanning driver, attempt parser, static resource processor, exception parser, interceptor, upload Parser, etc., if we want to use these components, we need to inject the relevant configuration of these components in the configuration file. After the configuration is injected, the SpringMVC factory loads these components during the execution process to achieve our purpose of using these components. So this is why it is popular.
Analysis of SpringMVC execution process

The above learned that the entrance to our execution process analysis is 核心的前端控制器,即web.xml, then we are qualified to understand what is configured in the front controller! as follows:

Front controller
image-20200719185840281

As you can see from the above figure, what is included in the front controller is to start the SpringMVC factory and the Spring factory at the same time, allowing the two factories to operate at the same time to process requests and respond. Since we want to analyze the underlying execution process of SpringMVC, we have to start with loading the SpringMVC factory DispatcherServlet. First enter the DispatcherServlet, view all methods of the source code, as shown in the following figure:

All methods of DispatcherServlet source code
image-20200719190557728
DispatcherServlet继承FrameworkServlet
image-20200719190959184

As shown in the picture above, I entered the DispatcherServlet. Since it is a Servlet, it must be a service method, because the Service method is the core of the Servlet. So I opened the IDEA method list to search for the service method, but failed. Although unsuccessful, I found two important clues, one is that there is a doSerivce method in the Servlet, and the other is that DispatcherServlet inherits FrameworkServlet. I think since the subclass does not have a service method, the parent class must have it, so I entered the FrameworkServlet to view the source The code, as shown in the figure below:

FrameworkServlet source code
image-20200719193120903

I am excited to find the service method in the parent class (FrameworkServlet), but I still feel happy too early . I don't know anything about the service method except the resolvemethod and method of obtaining the request processRequest. Then I discovered what the red arrow pointed at super.service(request, response);. What does this mean? This means that it inherits the service method owned by the parent class, so I clicked on the service method after the super period to view the source code. It was amazing to find that this class turned out to be HttpServlet. Obviously, our way of finding the service method has come to an end. There are two methods in it. One is the resolvemethod, which is the way to get the request. There is another method that I don’t know what it is, so I clicked in to view the source code, as shown below:

processRequest method source code
image-20200719193708541

Now that we went in to see the source code of the processRequest method, we need to find an important method. What is an important method? Generally, the method wrapped by the try block must be an important method, so I found the doService(request, response);method and continued to click to see the source code of the doService method, as shown in the following figure:

doService(request, response); method source code
image-20200719194003105

I was gradually losing patience. I was really surprised. After entering the doService method, I didn't jump to other classes, but still jumped to an empty doService(); method in this class. Alas, it is really not easy to find out~ I sighed. Calm down and think about it. The parent class has no implementation of empty methods, so the core logic code must be in the subclass. This is not polymorphism! So, I came to the conclusion that it’s hard to find the entrance logic code. Looking back, it still depends on the doService method in DispatcherServlet. At this time, I know that this will be a long road of exploration. So, with the mentality of exploring the principle, I once again clicked into the doSerivce method in the DispatcherServlet that I missed, as shown below:

The doService() method in DispatcherServlet
image-20200719195305154

Now that it is determined that this is the beginning of exploring the underlying principles, we are looking for important logic in the doServie() method, so I once again found a doDispatch(request, response);method named in the try block (omitting the various initialization and Storage domain data). On the way to explore the underlying principles, you will find closer and closer to the truth. Although this is destined to be a long process of exploration, I am willing. So, click to enter the source code in the doDispatch() method, as shown in the following figure:

doDispatch() method source code
image-20200719200052667

After walking into the source code of the doDispatch() method, I realized that I did not misunderstand you. Those marked with comments are some important execution logic methods. Next, we will analyze one by one, and gradually understand the execution process of SpringMVC. Since exploring the execution flow, Debug (Debug debugging function, Debug can clearly see the execution flow), so I getHandler()hit a breakpoint in the method line. The next step is to follow up the execution process and enter the getHandler()method, as shown in the following figure:

GetHandler method source code (note explanation: find and return a handler object for the current request)
image-20200719201557155

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

0 = {RequestMappingHandlerMapping}
image-20200719202203776
2 = {SimpleUrlHandlerMapping}
image-20200719202458924

As shown in the above figure, the RequestMappingHandlerMapping object identifies the @RequestMapping annotation in our Controller and the annotation path above each Handler. The SimpleUrlHandlerMapping object identifies the default servlet created by the driver for processing static resources, and the default servlet path for processing static resources is given /**, and it identifies this path. After the objects in the HanderMapping mapper have obtained the annotations for each Handler request path of the Controller layer through annotation recognition, they execute to the next line, as shown below:

getHandler method source code
image-20200719203457220

All Handlers can be found through annotations, all of which are stored in handlerMappingsit, so it traverses this object. Then obtain the corresponding Handler according to the respective request object and return the obtained corresponding Handler object as null. Continue down the execution, you will find such a thing, as shown below:

getHandler method
image-20200719204645324

Yes, you will find that the Handler that is about to return is an execution chain called HandlerExecutionChain. The execution chain contains the handler object to be returned and an interceptorList collection. There are two objects in the collection, and these two objects are interceptors. Therefore, whether you use the interceptor yourself or not (there are interceptors at the bottom of the interior), these interceptors and handler objects will be executed in a chain (interceptor first, handler object behind). The execution process follows the order of executing the interceptor first, and then returning and executing the handler object. Returned to the HandlerExecutionChain execution chain, then the execution chain is about to start! The question is, who exactly executes the interceptor and handler objects in turn? As shown below:

doDispatch() method source code
image-20200719210132545

After returning to the execution chain, execution continues until this line of code is executed, and the comment is interpreted as looking for a handler adapter for the current request object. If you have learned the adapter design pattern, it may be easier for you to understand it. It does not matter if you have not learned it. You can also understand the subsequent explanation. Knowing that it is looking for an adapter for the request object, then we continue to execute, and we get the following information:

getHandlerAdapter method source code
image-20200719210604037

The execution flow has entered the getHandlerAdaptermethod. From a distance, I can see that this method has a familiar feeling. Yes, it is very similar to the HandlerMapping mapper, and it is simply a twin brother. This method needs to find an adapter for its handler object based on the currently returned handler object. There are three adapters stored in the handlerAdapters collection object. Think about it when we get the execution chain in the mapper. Yes, they appear in pairs, and the object of the handler can continue execution only after finding the corresponding adapter. After finding the adapter paired with the current handler object, the adapter is returned. After the adapter returns, the following methods go through:

doDispatch() method source code
image-20200719211355102

After passing through this piece of code, the request method of the request object was obtained and a series of judgment operations were performed on it. Continue execution to the following, there is an if judgment below, which judges the execution applyPreHandlermethod, this method is the pre-method of the interceptor. After executing the front method of the interceptor, continue to execute downward. At this time, the following code should be executed:

doDispatch() method source code
image-20200719211927390

From this method, it can be seen that the haobject is the handler object at this time, indicating that the interceptor is executed before the handler object is executed, which also follows the order of the execution chain. Continue to execute, after completing the encapsulation of the request parameter object and the conversion of the Json string and the object in the response, an mv object is returned. So what is the mv object? In fact, it is the ModelAndView object defined above. After returning the mv object, the execution continues to execute the following important execution logic:

doDispatch() method source code
image-20200719213149039

In the execution process, the post method of the interceptor was judged and executed. After executing the post method, a series of judgments are made, and then the processDispatchResult(processdRequest, response, mappdeHandler, mv, dispatchException)method is executed . The method carries the request object, response object, handler object, ModelAndView object, etc., enter the source code of this method, and you will find it performs After a series of judgments, the ModelAndView object was rendered through the following methods:

render method source code
image-20200719213629854

After rendering the ModelAndView object and parsing the view, continue to follow up the method, because the victory is coming soon. As shown below:

render method source code
image-20200719213959635

Continue to execute, you will find that it begins resolveViewNameto resolve the view through methods. So, enter the method, as shown below:

resolveViewName method source code
image-20200719214336328

First, seeing the source code of this method, you can find that the viewResolversview resolver will parse the ModelAndView object and return a View object. Later, the View object will also be renderrendered by a method named as follows:

view.render()
image-20200719214907676

It can be seen that this View object is not simple. After it has been executed for some time, due to the request forwarding used when my web page is redirected, the source code of the page is as follows:

InternalResourceView source code
image-20200719215303749

Clicking on this method will find that the request forwarding we are familiar with is now read and parsed here spring-mvc.xml, and the path is spliced ​​for the internal default request forwarding forward:/XXX/XXX(this time it also parses the spring-mvc.xml configuration file Other components), as shown below:

Request forwarding (InternalResourceView.java)
image-20200719215453276

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

Redirection (RedirectView.java)
image-20200719215921537

Subsequently, after forwarding or redirecting to the JSP page (view layer), the data is rendered into HTML, and after the HTML content is rendered, it is output to the browser and responds, and displayed in the browser!

In this SpringMVC, I walked through the underlying execution process by interrupting debugging. I believe you will get a good result if you interrupt the debugging by yourself!

Internal components of SpringMVC
  • HandlerMapping (processor mapper)
  • HandlerAdapter
  • ViewResolver (view resolver)
SpringMVC default component initial loading

Above, we simply walked through the execution process of SpringMVC through Debug, but how did so many internal components come from? So, I found a method from DispatherServlet initStrategies, as follows:

initStrategies method source code
image-20200720214203411

Before the execution process starts, a series of initialization operations of internal components are done. Here we initHandlerMappingstrace back with the method to find the default configuration file of SpringMVC. Enter the initHandlerMappings method, because we did not configure (annotation or Bean tag), so the first two cases in this method will be skipped, will come to the bottom default case, call the getDefaultStrategies method, read the default configuration file.

initHandlerMappings method source code
image-20200720214539186
getDefaultStrategies method source code
image-20200720214701181

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

defaultStrategies source code
image-20200720214907843

This is the place to load the default configuration file. Click the DEFAULT_STRATEGIES_PATH constant to find the default configuration file.

DEFAULT_STRATEGIES_PATH constant
image-20200720215021940

So I found a way to find this configuration file, which initialized various components, you can check:

DispatcherServlet.properties configuration file
image-20200720215320968

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_44170221/article/details/107497117