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.
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
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.
DoDispatch, literally, is a method that distributes requests, and the core logic is there
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);
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
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 ());
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
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
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);
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
// This determines whether to forward or redirect, or change to another view
view.render(mv.getModelInternal(), request, response);Copy the code
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
Now, the sequence of interceptor execution is defined by applyPreHandle, applyPostHandle, triggerAfterCompletion, and the following diagram
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