您现在的位置是:首页 >其他 >Spring MVC(3)-MVC执行流程分析网站首页其他
Spring MVC(3)-MVC执行流程分析
简介Spring MVC(3)-MVC执行流程分析
执行流程
- 用户发起请求,请求到达DispatcherServlet。
DispatcherServlet#doDispatch
分发处理请求;AbstractHandlerMapping#getHandler
匹配Request处理器;HandlerExecutionChain#applyPreHandle
执行HandlerInterceptor
前置校验;DispatcherServlet#getHandlerAdapter
获取处理器适配器,核心逻辑,包含Method参数转换、把Method返回值转换并且写入Response;HandlerExecutionChain#applyPostHandle
执行HandlerInterceptor
后置处理;DispatcherServlet#processDispatchResult
异常、HandlerInterceptor#afterCompletion
处理。FrameworkServlet#publishRequestHandledEvent
发布一个事件,表示该请求处理完毕,无论成功与否。
DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
/* TODO
预处理:
1. 获取HandlerMethod和过滤器链的包装类(url-hanlderMethod映射):HandlerExecutionChain,里面包含了handlerMethod对象
2. 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式
调用链:
1. 前置拦截,正向遍历调用,若有返回false,则调用后置处理,返回。
interceptor.preHandle(request, response, this.handler)
triggerAfterCompletion(request, response, null);
2. 根据HandlerAdapter获取真正的处理类,执行:((Controller) handler).handleRequest(request, response)
3. 中置拦截,反向遍历调用。 interceptor.postHandle(request, response, this.handler, mv);
4. 视图渲染,在视图渲染之后,会在视图渲染方法中调用后置处理。
render(mv, request, response);
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
*/
// 异步管理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查是否文件上传
//检查方式:校验contentType是否已 multipart/ 开头
//如果是 文件上传,request转为 StandardMultipartHttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 重点:获取封装了 handlerMethod、拦截器的执行链封装 HandlerExecutionChain。
// @Controller 使用 RequestMappingHandlerMapping
// 包含ConversionServiceExposingInterceptor、ResourceUrlProviderExposingInterceptor拦截器
// handler为HandlerMethod
mappedHandler = getHandler(processedRequest);
//匹配不到处理器,如果throwExceptionIfNoHandlerFound=false(默认false)返回404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// TODO 获取跟HandlerMethod匹配的HandlerAdapter对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// TODO 前置过滤器,如果为false则直接返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// TODO 重点,调用到Controller具体方法,核心方法调用。
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// TODO 执行中置拦截
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// TODO 处理结果,这里执行了后置拦截。在前面的流程里捕获了业务方法执行过程中抛出的异常。
// 如果上面的流程中抛出了异常,则dispatchException一定有值。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
AbstractHandlerMapping#getHandler
获取适配当前Request的HandlerExecutionChain
。
处理流程:
- 查询可以处理Request的handler,@Controller标注的类handler为
HandlerMethod
; - 构建
HandlerExecutionChain
类,包含handler、HandlerInterceptor
; - 是否CORS请求,如果是预验证(使用
OPTIONS
请求并且header包含Access-Control-Request-Method
)使用PreFlightHandler
包装handler;如果不是预验证,增加一个CorsInterceptor
拦截器。
/**DispatcherServlet#getHandler 方法*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// handlerMappering实例
if (this.handlerMappings != null) {
// 在 DispatcherServlet 初始化的时候,会将handlerMappings的值,赋值到这里。
for (HandlerMapping mapping : this.handlerMappings) {
// 获取HandlerMethod和拦截器链的包装类
//@Controller 使用 RequestMappingHandlerMapping
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
/**AbstractHandlerMapping#getHandler 方法
匹配handler并且使用HandlerExecutionChain 包装*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// TODO 获取 HandlerMethod
// @Controller标注的类handler为HandlerMethod
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 将 handlerMethod,包装到 HandlerExecutionChain 中。
// HandlerExecutionChain除包含handlerMethod外,还装配了当前请求的HandlerInterceptor
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
//是否CORS请求,通过header中是否有Origin
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
DispatcherServlet#getHandlerAdapter
获取跟HandlerMethod匹配的HandlerAdapter对象。
Spring MVC装配了3个HandlerAdapter:
RequestMappingHandlerAdapter
:主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller
的这类处理器HttpRequestHandlerAdapter
:主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler
接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。SimpleControllerHandlerAdapter
:Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController
.
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里是典型的的策略模式
// 遍历所有的 handlerAdapters,并调用其 supports(),如果有 adapter 支持这个 handlerMethod,就返回这个 adapter。
// handlerAdapters包含:
// RequestMappingHandlerAdapter:主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器
// HttpRequestHandlerAdapter:主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
// SimpleControllerHandlerAdapter:Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController.
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
HandlerExecutionChain#applyPreHandle
执行HandlerInterceptor
的前置校验,任何一个返回false即停止往下执行。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//默认有两个拦截器:
//ConversionServiceExposingInterceptor:
// 用于向请求添加一个属性,属性名称为ConversionService.class.getName(),值是Spring MVC配置定义的一个类型转换服务。该类型转换服务会在请求处理过程中用于请求参数或者返回值的类型转换。
//ResourceUrlProviderExposingInterceptor:
// 用于向请求添加一个属性,属性名称为ResourceUrlProvider.class.getName(),值是Spring MVC配置定义的一个资源URL提供者对象ResourceUrlProvider。
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 遍历执行拦截器的前置方法,只要有一个返回了false,就返回false。
// 每次执行一个前置拦截后,就将interceptorIndex+1,当有前置方法返回false时,执行triggerAfterCompletion。
if (!interceptor.preHandle(request, response, this.handler)) {
// 倒序执行后置拦截,起始索引是 interceptorIndex,即如果也有前置拦截执行失败了,
// 那么相应的这个失败的及之后的拦截器的后置拦截就不会执行。
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
HandlerAdapter#handle
/**调用具体的业务逻辑*/
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
/**RequestMappingHandlerAdapter#handleInternal*/
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//检查请求方法是否支持和session是否存在
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
// synchronizeOnSession=false(默认)
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// TODO Controller里面具体方法调用,重点看
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
/**RequestMappingHandlerAdapter#invokeHandlerMethod
把request转换成Method的参数、调用Method、Method返回结果处理*/
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取数据绑定工厂 @InitBinder注解支持,没太多用
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// Model工厂,收集了@ModelAttribute注解的方法
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));
// 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法
// 把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了
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);
}
// TODO 重点:解析Request参数为目标方法参数、校验目标方法参数、Controller方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
/**ServletInvocableHandlerMethod#invokeAndHandle
调用具体业务逻辑、把Method返回值写入response*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// TODO 重点:具体方法调用逻辑
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// TODO 使用返回值处理器,对返回值进行处理
// returnValueHandlers 使用 HandlerMethodReturnValueHandlerComposite 实例
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
/**HandlerMethodReturnValueHandlerComposite#handleReturnValue
查找具体的handler并且处理返回值*/
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// TODO 查找返回值处理器,策略模式的一种运用
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
// 如果不存在返回值处理器,则跑出异常
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 对返回值进行处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
/**HandlerMethodReturnValueHandlerComposite#selectHandler*/
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 遍历容器中所有的返回值处理器,判断是否支持,如果有返回值处理器支持这个返回值,则返回此处理器。
// 这也是策略模式的一种运用。
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
//@ResponseBody标注使用RequestResponseBodyMethodProcessor
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
/**RequestResponseBodyMethodProcessor#handleReturnValue
把Method返回值写入response*/
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 使用消息转换器写出响应信息。
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
AbstractMessageConverterMethodArgumentResolver#validateIfApplicable
AbstractMessageConverterMethodArgumentResolver#validateIfApplicable
校验 @Validated
注解标记的参数,实际由DataBinder#validate(java.lang.Object...)
校验,DataBinder
代理Validator
列表,遍历Validator
列表对参数进行校验。
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation ann : annotations) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
binder.validate(validationHints);
break;
}
}
}
HandlerExecutionChain#applyPostHandle
执行HandlerInterceptor
后置处理。
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 如果存在拦截器,倒序执行中置拦截。能执行到这个方法,说明所有的前置拦截都成功执行了。
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
DispatcherServlet#processDispatchResult
主要用来处理前面返回的结果,其中包括处理异常、渲染页面、触发 Interceptor 的 afterCompletion
方法三部分内容,处理的异常是在处理请求 doDispatch
方法的过程中产生。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果前面的流程中抛出了异常,在这里会进行处理。
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
// TODO 异常处理
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
//执行页面渲染操作
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// Handler请求处理完,触发Interceptor的afterCompletion
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
FrameworkServlet#publishRequestHandledEvent
发布一个事件,表示该请求处理完毕,无论成功与否。
/**
* 发布一个事件,表示该请求处理完毕,无论成功与否
* @param request 当前request
* @param response 当前response
* @param startTime 请求处理开始时间戳毫秒
* @param failureCause 失败原因(抛出的异常,可能为null)
*/
private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,
long startTime, @Nullable Throwable failureCause) {
//如果允许发布事件并且关联的IoC容器不为null,那么无论我们是否成功,都发布一个事件。
if (this.publishEvents && this.webApplicationContext != null) {
//计算请求处理花费的时间
long processingTime = System.currentTimeMillis() - startTime;
//通过IoC容器发布ServletRequestHandledEvent事件,包含各种请求信息
//这样我们就可以使用Spring的事件监听机制来监听这个事件进而来监听这个请求了
this.webApplicationContext.publishEvent(
//this:事件源,当前DispatcherServlet对象
new ServletRequestHandledEvent(this,
//请求路径、ip地址
request.getRequestURI(), request.getRemoteAddr(),
//请求方法、ServletName
request.getMethod(), getServletConfig().getServletName(),
//SessionId、username
WebUtils.getSessionId(request), getUsernameForRequest(request),
//请求处理时间、失败原因、响应状态码
processingTime, failureCause, response.getStatus()));
}
}
类信息
HandlerMethodArgumentResolver
:将方法参数解析为参数值;HandlerMethodReturnValueHandler
:用于处理从Controller方法的调用返回的值;RequestResponseBodyMethodProcessor
:实现HandlerMethodArgumentResolver
、HandlerMethodReturnValueHandler
,处理@RequestBody
注解
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。