Introduction to Spring-MVC Core Architecture

First, the core process

img

  1. Step 1: Initiate the request to the method in the front controller ( DispatcherServlet) doDispatch, and then delegate to the doDispatchmethod for processing.
  2. getHandlerStep 2: Afterwards, the method will be requested and HandlerMappingsearched Handler(by configuration and annotation)
  3. Step 3: After finding Handler, the request will be encapsulated into an HandlerExecutionChainobject (including a Handlerprocessor (page controller) object, multiple HandlerInterceptorinterceptor objects) and returned.
  4. Step 4: Then obtain the processor adapter getHandlerAdapterthat supports this processing through the method .handlerHandlerAdapter
  5. Step 5: The obtained handler adapter HandlerAdapterwill execute the Handler according to the result of the adaptation, usually by the Handler RequestMappingHandlerAdapter#handleInternal.
  6. Step 6: HandlerReturn to the adapter after the execution is completed . The implementation ModelAndViewhere Handleris usually the implementation written by ourselves controller.
  7. Step 7: The processor adapter returns to the front controller ModelAndView( ModelAndViewis an underlying object of the springmvc framework, including Model and view)
  8. 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.
  9. Step 9: The view resolver returns the View to the front controller
  10. Step 10: The front-end controller performs view rendering (the view rendering fills the model data (in the ModelAndView object) into the request field)
  11. Step 11: The front controller responds to the user with the result

Second, the core components

1,DispatcherServlet

DispatcherServlet​It is DispatcherServletYes Servlet(it inherits from the HttpServletbase 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.

DispatcherServletAfter 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 HandlerMappingon 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 DispatcherServletunnecessary 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. HandlerAdapterThe main purpose is to shield many details DispatcherServletbetween 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 HandlerExecutionChainobject (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 getHandlerthe method, take out all the HandlerMappinginterface and traverse, and let HandlerMappingthe 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 HandlerMappinginterface . As AbstractHandlerMappingcan be seen from the method in the implementation class, the handlerobject , 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 getHandlerExecutionChainmethod will first get it into handlerLoad HandlerExecutionChain, and then add qualified interceptors to the HandlerExecutionChainhandler 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. HandlerExecutionChainAfter 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, HttpRequestHandleretc.) have multiple implementation methods, such as inheritance Controller, annotation-based controller methods, and HttpRequestHandlermethods. 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 HandlerAdapterare three methods, namely supports, handleand 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 RequestMappingHandlerAdapterthis implementation. It should be the implementation mainly used by springMVC at present, for method-level mapping matching processing.

RequestMappingHandlerAdapterInherited from an AbstractHandlerMethodAdapterabstract class, AbstractHandlerMethodAdapterbut HandlerAdapteran abstract implementation of an interface.

Inheritance relationship: HandlerAdapter--> AbstractHandlerMethodAdapter--> RequestMappingHandlerAdapter.

​Participation timing: When a request is HandlerMappingprocessed and it comes to the processor adapter for processing:

1. First call getHandlerAdapterthe method to get the HandlerAdapterobject, and then call handlethe 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#handleand call handleInternalit, this is an abstract method

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
	throws Exception {
	return handleInternal(request, response, (HandlerMethod) handler);
}

RequestMappingHandlerAdapter3. At this time , the handleInternalmethod 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 invokeHandlerMethodour own writing , as well as other configurations for processingControllerRequestMapping

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#invokeAndHandlemethod, 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, Viewor 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 HandlerInterceptorsor web request interceptors can be configured WebRequestInterceptorsand 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 Handleassembled, 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 @Controllerwith @xxxMappingannotations such as and .

4.4 File upload (MultipartResolver)

​to be added

5. REST related components

5.1 HandlerMethodArgumentResolver

Responsibilities: Used to parse HandlerMethodparameter , process them into Handlerusable 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 HandlerMethodreturn 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

  1. received a request
  2. Interceptor for request interception
  3. HTTP message converter for request processing
  4. Method parameter parser for processing
  5. User-written controller Controller handles processing
  6. Method return value parser for return value processing (to be confirmed)
  7. HTTP message converter for return value processing (to be confirmed)
  8. The interceptor performs return value interception processing (to be confirmed)
  9. 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

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324139155&siteId=291194637