First, the core process
- Step 1: Initiate the request to the method in the front controller (
DispatcherServlet
)doDispatch
, and then delegate to thedoDispatch
method for processing. getHandler
Step 2: Afterwards, the method will be requested andHandlerMapping
searchedHandler
(by configuration and annotation)- Step 3: After finding
Handler
, the request will be encapsulated into anHandlerExecutionChain
object (including aHandler
processor (page controller) object, multipleHandlerInterceptor
interceptor objects) and returned. - Step 4: Then obtain the processor adapter
getHandlerAdapter
that supports this processing through the method .handler
HandlerAdapter
- Step 5: The obtained handler adapter
HandlerAdapter
will execute the Handler according to the result of the adaptation, usually by the HandlerRequestMappingHandlerAdapter#handleInternal
. - Step 6:
Handler
Return to the adapter after the execution is completed . The implementationModelAndView
hereHandler
is usually the implementation written by ourselvescontroller
. - Step 7: The processor adapter returns to the front controller
ModelAndView
(ModelAndView
is an underlying object of the springmvc framework, including Model and view) - Step 8: The front-end controller requests the view parser to perform view parsing. It is easy to replace other view technologies, such as thymeleaf, json, etc., by using this strategy. You only need to change the view parser.
- Step 9: The view resolver returns the View to the front controller
- Step 10: The front-end controller performs view rendering (the view rendering fills the model data (in the ModelAndView object) into the request field)
- Step 11: The front controller responds to the user with the result
Second, the core components
1,DispatcherServlet
DispatcherServlet
It is DispatcherServlet
Yes Servlet
(it inherits from the HttpServlet
base class), but can do more than that. It integrates seamlessly with the Spring IoC container, which means that you can use any feature provided by Spring in Spring MVC.
UseDispatcherServlet
special beans to handle requests, render views, etc. These special beans are part of the framework and depend on these special beans for its initialization. Spring MVC maintains a default list of beans that the framework will use if you don't configure it specifically.
DispatcherServlet
After subdivision, three functions can be sorted out:
- Intercept HTTP requests and hand them over to the Spring MVC framework for processing
- Handling the calling relationship
- Initialize and assemble the various components of Spring MVC
2. List of important component beans
Component Bean Type | illustrate |
---|---|
HandlerMapping | Processor mapping. It maps incoming container requests to specific processors and a series of pre-processors and post-processors (i.e. processor interceptors) according to certain rules. The exact rules vary depending HandlerMapping on the implementation of the class. One of its most common implementations allows you to add annotations to controllers to configure request paths. Of course, other implementations also exist. |
HandlerAdapter | processor adapter. After getting the handler corresponding to the request, the adapter will be responsible for calling the handler, which makes it DispatcherServlet unnecessary to care about the specific calling details. For example, if you want to call a controller based on annotation configuration, you need to parse some corresponding information from many annotations before calling. For example, a Controller that invokes an annotation implementation needs to parse its associated annotation. HandlerAdapter The main purpose is to shield many details DispatcherServlet between and . |
HandlerExceptionResolver | Handler exception parser, which is responsible for mapping caught exceptions to different views, and also supports more complex exception handling code. |
ViewResolver | View parser, parses the actual View object from the logical view name of character type returned by the Handler, which outputs the rendered content to the HTTP response. |
MultipartResolver | Parse multi-part transmission requests, such as supporting file uploads through HTML forms, etc. |
3. Main components
3.1 HandlerMapping
Responsibility : HandlerMapping
The role is to find the corresponding according to the current request Handler
, and encapsulate the Handler
(executor) and HandlerInterceptor
(interceptor) into the HandlerExecutionChain
object (handler execution chain, consisting of the handler object and the handler interceptor) and return.
Participation timing: When the request arrives DispatcherServlet#doDispatch
, the handler will be determined according to the current request. The detailed process is as follows:
1. First call getHandler
the method, take out all the HandlerMapping
interface and traverse, and let HandlerMapping
the instance of the interface try to find it according to the way it implements the class Handler
.
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
//...省略
// 查找给定请求的处理程序
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
2. There is only one method inside the HandlerMapping
interface . As AbstractHandlerMapping
can be seen from the method in the implementation class, the handler
object , and then the handlerhandler
execution chain will be obtained through the request and .HandlerExecutionChain
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
//...省略
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//...省略
// 获取 处理程序拦截器 HandlerInterceptor并进行组装,
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
3. The getHandlerExecutionChain
method will first get it into handler
Load HandlerExecutionChain
, and then add qualified interceptors to the HandlerExecutionChain
handler and return.
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//获取拦截器
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
4. HandlerExecutionChain
After the object is finally obtained, it is handed over to the HandlerAdapter
(processor adapter) for the next step of processing.
3.2 HandlerAdapter and Execution Process
Responsibilities : Spring MVC's handlers ( Controller
, HttpRequestHandler
etc.) have multiple implementation methods, such as inheritance Controller
, annotation-based controller methods, and HttpRequestHandler
methods. Due to the different implementation methods, the calling method is uncertain. If you write the call normally, you need to use multiple if elses to judge the instance of, and then add the implementation method, you need to modify the source code, which does not meet the principle of opening for extension and closing for modification, so Spring MVC provides a processor adapter ( HandlerAdapter
), which shields the The differences of various handlers are handled in a unified way.
There HandlerAdapter
are three methods, namely supports
, handle
and getLastModified
,
public interface HandlerAdapter {
/**
* 判断是否支持传入的handler
*/
boolean supports(Object handler);
/**
* 使用给定的handler处理请求
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 返回上次修改时间,可以返回-1表示不支持
*/
long getLastModified(HttpServletRequest request, Object handler);
}
It isHandlerAdapter
an interface and there are many ways to implement it, but in our usual use, we generally only use RequestMappingHandlerAdapter
this implementation. It should be the implementation mainly used by springMVC at present, for method-level mapping matching processing.
RequestMappingHandlerAdapter
Inherited from an AbstractHandlerMethodAdapter
abstract class, AbstractHandlerMethodAdapter
but HandlerAdapter
an abstract implementation of an interface.
Inheritance relationship: HandlerAdapter
--> AbstractHandlerMethodAdapter
--> RequestMappingHandlerAdapter
.
Participation timing: When a request is HandlerMapping
processed and it comes to the processor adapter for processing:
1. First call getHandlerAdapter
the method to get the HandlerAdapter
object, and then call handle
the method for the next step.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//...省略
// 获取到匹配的 HandlerAdapter 对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//...省略
//进行调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//...省略
}
2, then it will enter the method AbstractHandlerMethodAdapter#handle
and call handleInternal
it, this is an abstract method
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
RequestMappingHandlerAdapter
3. At this time , the handleInternal
method implementation in the implementation class will be called ,
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//...省略
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
//...省略
return mav;
}
4. Call the method, which will call the method logic in invokeHandlerMethod
our own writing , as well as other configurations for processingController
RequestMapping
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//设置参数处理器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//设置返回值理器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 是否是异步方法
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 调用并进行处理
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 返回值ModelAndView处理
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
5. Execute the ServletInvocableHandlerMethod#invokeAndHandle
method, call and process it
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.处理调用Controller中的具体方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 2.设置返回状态码
setResponseStatus(webRequest);
//3.当前请求无返回值或者返回值中包含错误,则将请求完成标识设置为true并返回
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// 4.当前请求有返回值且无错误信息,则将请求完成标识设置为false,并继续处理当前请求
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
//// 选取合适的HandlerMethodReturnValueHandler,并处理返回值
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
The most important of these is the first step invokeForRequest
:
public Object invokeForRequest(NativeWebRequest request,
@Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/**
* 注意这里不一定都是解析@RequestMapping方法的参数,
* 也有可能会解析@InitBinder方法的参数
*
* 所以下面的doInvoke方法也并不一定调用具体的@RequestMapping方法,
* 也有可能调用@InitBinder方法进行参数的解析绑定
*/
// 获取并解析请求参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 调用系统反射方法进行执行
return doInvoke(args);
}
3.3 View resolver (ViewResolver)
Responsibility : After the processing adapter processes the request, it will go to the view resolver (ViewResolver) for further processing. The handler methods of all controllers in Spring MVC must return the name of a logical view, whether it is an explicit return (such as returning a String
, View
or object) or implicit return (such as returning based on a contract). Views in Spring are identified by a view name and are rendered by the view resolver.
the rest to be added
4. Other components
4.1 Interceptors
Responsibilities: Interceptors such as handler interceptors HandlerInterceptors
or web request interceptors can be configured WebRequestInterceptors
and configured to intercept all requests entering the container, or restrict to URL paths that match a specific pattern. There is nothing to say about this, everyone is familiar with it, and we often use it when we extend the functionality of Spring MVC.
Participation timing: When the processor map is Handle
assembled, the interceptors will be assembled into a list, and then when the processor adapter is processed, the interceptors will be executed according to the settings, and the execution of the request arrival interceptor is REST相关组件
before the following, The return process is described below REST相关组件
.
How to use: see the introduction in Extending SpringMVC
4.2 HandlerExceptionResolver
Responsibilities: Handle abnormal requests. Our company has used the unified exception interception method ( @controlleradvice
+ @ExceptionHandler
), which is no longer used, and there is no need to introduce it.
When to participate: when the request is abnormal.
How to use: slightly
4.3 Specific processing request controller (Controller/Handler)
Responsibilities: The controller you write is the processor that handles requests. This does not need to be introduced, and everyone uses it every day.
Timing of participation: When the processor adapter is in progress, it will match the request processor we wrote and process it.
How to use: Write it yourself, declare it @Controller
with @xxxMapping
annotations such as and .
4.4 File upload (MultipartResolver)
to be added
5. REST related components
5.1 HandlerMethodArgumentResolver
Responsibilities: Used to parse HandlerMethod
parameter , process them into Handler
usable parameter data,
Participation timing: When the request arrives and the parameters are to be processed, the matching processor will be found in the method parameter parser list to process the parameters.
How to use: see the introduction in Extending SpringMVC
5.2 HandlerMethodReturnValueHandler
Responsibilities: Used to parse the HandlerMethod
return value into HTTP response content
Timing of participation: When the method is processed and the return value is obtained, a matching processor will be found in the method return value parser list, and the return value will be processed.
How to use: see the introduction in Extending SpringMVC
5.3 HTTP Message Converter (HttpMessageConverter)
Responsibilities: HTTP message converter for deserializing HTTP requests or serializing responses. This component is method level,
Participation timing: When the request arrives and when the processing is completed, the data can be converted and processed. The time to process the request data is 处理方法参数解析器
before and before the return value is processed 在方法返回值解析器
.
How to use: see the introduction in Extending SpringMVC
6. The running sequence of some components
- received a request
- Interceptor for request interception
- HTTP message converter for request processing
- Method parameter parser for processing
- User-written controller Controller handles processing
- Method return value parser for return value processing (to be confirmed)
- HTTP message converter for return value processing (to be confirmed)
- The interceptor performs return value interception processing (to be confirmed)
- return request result
3. Common annotations (just understand)
request and response
annotation | illustrate | Spring Framework version |
---|---|---|
@RestController | Equivalent to @Controller +@ResponseBody |
4.0 + |
@RequestMapping | Application Controller Mapping Annotation Declaration | 2.5+ |
@xxxMapping | equal to@RequestMapping(method =RequestMethod.XXX) |
4.3+ |
@RequestParam | Get request parameters | 2.5+ |
@RequestHeader | get request headers | 3.0+ |
PathVariable | Get request path variable | 3.0+ |
@RequestBody | Get the complete request body content | 3.0+ |
@ResponseBody | Response body declaration | 2.5+ |
@PostConstruct | will be called automatically after dependency injection is complete | JavaEE annotations |
Project Recommendation: Based on Spring Cloud Alibaba technology, a distributed microservice development platform including basic functions, OA, payment, marketing and other modules