Spring MVC 生命周期

说到 Java 开发,现在最流行的框架是什么呢?90% 以上的程序员应该会说是 Spring,而作为 Spring Web 开发的利器 Spring MVC,更是各位 Java Web 开发者的心头好。所以为了能更好、更简单地开发一个 Web 项目,了解下 Spring MVC 的底层逻辑是很有必要的,这将帮助我们了解 Spring MVC 提供的各种扩展点,用更加优雅的方式来实现我们的项目。

整体逻辑

Spring MVC 的整体处理过程如上图所示,调用链还是比较清晰。

  1. 当请求过来之后,DispatcherServlet 通过 HandlerMapping 获取一个合适的 Handler 来处理请求,这里将获得 HandlerMethod 对象(Controller + Method 封装),并生成 HandlerExecutionChain 对象
  2. 依据 HandlerMethod ,遍历 DispatcherServlet 中注入的 HandlerAdapter,获的合适的 HandlerAdapter 对象
  3. 调用 HandlerAdapter 对象的 handler() 方法进行实际的业务处理,HandlerAdapter 对象中,主要依靠 ServletInvocableHandlerMethod 对象来处理参数的解析、业务调用、返回值的处理等
  4. HandlerAdapter 处理完之后,将返回 ModelAndView 对象
  5. 如果过程中发生异常将调用 HandlerExceptionResolver 处理异常
  6. 使用合适的 ViewResolver 解析 View,并使用 View 进行结果渲染

辅助类及入口

下面我们一起通过源码来看下上面的过程,源码版本基于"spring-webmvc-5.2.8.RELEASE"。

辅助类

下面是我读源码过程中用到的相关类。

kotlin 复制代码
/**
 * Spring MVC 生命周期示例
 * @author 鱼蛮 on 2019/2/15
 **/
@Slf4j
@RestController
public class SpringMvcLifeCycleTestController {

    /**
     * 用于演示 Spring Mvc 的生命周期
     *
     * @param date       PropertyEditorSupport 处理结果
     * @param mvcRequest HandlerMethodArgumentResolver 处理结果
     * @return {@link java.lang.String}
     */
    @GetMapping(value = "/mvc")
    public MvcResponse mvc(@RequestParam("date")Date date, MvcRequest mvcRequest) {
        System.out.println("4.call controller,date:" + date + ",params:" + mvcRequest);
        return new MvcResponse("成功");
    }
    
    @Data
    public static class MvcRequest {
        private Long id;
        private String name;
    }

    @Data
    public static class MvcResponse {
        private String data;

        public MvcResponse(String data) {
            this.data = data;
        }
    }
}
less 复制代码
/**
 * HandlerInterceptorAdapter 使用示例
 *
 * @author 鱼蛮 on 2019/2/15
 **/
public class HandlerInterceptorAdapterTest extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) {
        System.out.println("1.HandlerInterceptor preHandle");
        return true;
    }

    @Override
    public void postHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler,
                           @Nullable ModelAndView modelAndView) {
        System.out.println("6.HandlerInterceptor postHandle");

    }

    @Override
    public void afterCompletion(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler,
                                @Nullable Exception ex) {
        System.out.println("7.HandlerInterceptor afterCompletion");
    }
}
arduino 复制代码
/**
 * PropertyEditorSupport 使用示例
 *
 * @author 鱼蛮 on 2019/2/15
 **/
@ControllerAdvice
public class EditorTest {

    /**
     * 注册 {@link Date} 类型解析.
     *
     * @param binder    数据绑定器
     * @param request   request
     */
    @InitBinder
    public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(Date.class, new DateEditor());

        // 统一去除String参数中的前后空格
        StringTrimmerEditor stringTrimmer = new StringTrimmerEditor(true);
        binder.registerCustomEditor(String.class, stringTrimmer);
    }

    /**
     * 日期字段自动转 java.util.Date
     **/
    @Slf4j
    public class DateEditor extends PropertyEditorSupport {

        /** 常规日期时间格式 */
        public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        /** 精简日期时间格式 */
        public static final String SIMPLE_DATETIME_PATTERN = "yyyyMMddHHmmss";

        /** 常规日期格式 */
        public static final String DATE_PATTERN = "yyyy-MM-dd";

        /** 精简日期格式 */
        public static final String SIMPLE_DATE_PATTERN = "yyyyMMdd";

        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            if (StringUtils.isBlank(text)) {
                setValue(null);
                return;
            }

            Date date = null;
            try {
                date = DateUtils.parseDate(text, DATETIME_PATTERN, SIMPLE_DATETIME_PATTERN, DATE_PATTERN, SIMPLE_DATE_PATTERN);
            } catch (ParseException e) {
                log.warn(String.format("fail to parse java.util.Date type with value: %s", text), e);
            }
            System.out.println("2.PropertyEditor");
            setValue(date);
        }
    }
}
less 复制代码
/**
 *  HandlerMethodArgumentResolver 使用示例
 *
 * @author 鱼蛮 on 2019/2/15
 **/
public class HandlerMethodArgumentResolverTest implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(@Nonnull MethodParameter methodParameter) {
        return MvcRequest.class == methodParameter.getParameterType();
    }

    @Override
    public Object resolveArgument(@Nonnull MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  @Nonnull NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
        String id = nativeWebRequest.getParameter("mvcParams.id");
        String name = nativeWebRequest.getParameter("mvcParams.name");
        MvcRequest mvcRequest = new MvcRequest();
        mvcRequest.setId(Optional.ofNullable(id).map(Long::parseLong).orElse(null));
        mvcRequest.setName(name);
        System.out.println("3.HandlerMethodArgumentResolver");
        return mvcRequest;
    }
}
less 复制代码
/**
 * ResponseBodyAdvice 使用示例
 *
 * @author 鱼蛮 on 2019/2/15
 **/
@ControllerAdvice
public class ResponseBodyAdviceTest implements ResponseBodyAdvice<MvcResponse> {
    @Override
    public boolean supports(@Nonnull MethodParameter returnType, @Nonnull Class converterType) {
        return returnType.getParameterType() == MvcResponse.class;
    }

    @Override
    public MvcResponse beforeBodyWrite(MvcResponse body, @Nonnull MethodParameter returnType,
                                       @Nonnull MediaType selectedContentType,
                                       @Nonnull Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                       @Nonnull ServerHttpRequest request, @Nonnull ServerHttpResponse response) {

        System.out.println("5.ResponseBodyAdvice");
        return new MvcResponse(Optional.ofNullable(body).map(e -> e.getData() + "_advice").orElse(null));
    }
}

DispatchServlet#doDispatch()

源码的入口也很好找,因为 Spring MVC 是基于 Servlet 规范的,所以 DispartchServlet 继承自 HttpServlet,通过的 HttpServelt 的入口很容易找到最终的调用入口是 DispatchServlet#doDispatch() 。这个方法就是整个 Spring MVC 的核心处理过程。

ini 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 获取处理请求的 HandlerExecutionChain 对象
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 获得处理请求的 HandlerAdapter 对象
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            ... ...

                // 调用 HandlerInterceptor 的 preHandler() 方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

            // 实际的请求处理
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            ... ...
                // 调用 HandlerInterceptor 的 postHandler() 方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            ... ...
            }
        // 执行 ModelAndView 的解析、渲染
        // 调用 HandlerInterceptor 的 afterCompletion() 方法
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    ... ...
}

过程解读

DispatchServlet#getHandler()

首先是调用 DispatchServlet#getHandler() 方法来获得 HandlerExecutionChain 对象。这个其实主要就是通过遍历已经注入的类型为 List 的 handlerMappings 属性,来找一个合适的 HandlerMapping,再通过 HandlerMapping 来处理,对普通的请求基本都适用 RequestMappingInfoHandlerMapping。

RequestMappingInfoHandlerMapping#getHandler()

getHandlerInternal()

RequestMappingInfoHandlerMapping 中将首先调用 getHandlerInternal() 方法,通过请求中的 URL 地址,获得相应的 HandlerMethod 对象,而 HandlerMethod 里面包装的就是实际的业务逻辑处理类 Controller 及 Method 等信息。

java 复制代码
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根据请求的 URL 去找最合适的 HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

getHandlerExecutionChain()

这一步将获得一个 HandlerExecutionChain 对象,会将上一步中获得的 HandlerMethod 对象作为属性注入其中。并且根据请求 URL 匹配 HandlerInterceptor(拦截器),组装到 HandlerExecutionChain 对象中,后面都是使用 HandlerExecutionChain 来间接触发 HandlerInterceptor。

java 复制代码
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            // 根据请求的 URL 获取匹配的 HandlerInterceptor,加入到 chain 中
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

DispatchServlet#getHandlerAdapter()

这一步其实很简单,就是通过上面获取的 HandlerExecutionChain 对象中的 handler 属性(HandlerMethod 对象)来获取支持的 HandlerAdapter 对象。

这里最终获得的 HandlerAdapter 对象是:RequestMappingHandlerAdapter。

kotlin 复制代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
}

HandlerExecutionChain#applyPreHandle()

在调用实际业务处理代码之前,会先执行 HandlerExecutionChain#applyPreHandle() 方法,而这个就会调用上面匹配的拦截器 HandlerInterceptor 中的 preHandle() 方法。如果返回值不为 true,将结束请求的处理。

RequestMappingHandlerAdapter#handle()

获得了 RequestMappingHandlerAdapter 对象之后,就需要调 RequestMappingHandlerAdapter#handle() 方法进行实际的业务调用,及相关处理。这个方法只是一个对外接口方法,里面将调用真正的实现方法 handleInternal(),继续往下,将调用核心的逻辑处理方法 invokeHandlerMethod()。

invokeHandlerMethod()

kotlin 复制代码
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        ... ...
		// 初始化 ServletInvocableHandlerMethod 对象
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 核心属性设置 HandlerMethodArgumentResolver
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 核心属性设置 HandlerMethodReturnValueHandler
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 核心属性用于参数解析,PropertyEditorSupport
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        ... ...
        // 执行业务逻辑方法,并且处理结果
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        ... ...

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    ... ...
}

在 invokeHandlerMethod() 方法中,首先会调用 createInvocableHandlerMethod() 方法,创建 ServletInvocableHandlerMethod 对象。

ini 复制代码
protected HandlerMethod(HandlerMethod handlerMethod) {
    Assert.notNull(handlerMethod, "HandlerMethod is required");
    this.bean = handlerMethod.bean;
    this.beanFactory = handlerMethod.beanFactory;
    this.beanType = handlerMethod.beanType;
    this.method = handlerMethod.method;
    this.bridgedMethod = handlerMethod.bridgedMethod;
    this.parameters = handlerMethod.parameters;
    this.responseStatus = handlerMethod.responseStatus;
    this.responseStatusReason = handlerMethod.responseStatusReason;
    this.description = handlerMethod.description;
    this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
}

一路追踪下去,会发现 ServletInvocableHandlerMethod 继承自 HandlerMethod,创建的时候会将上面获得的 HandlerMethod 对象传入,读取核心属性来创建 ServletInvocableHandlerMethod 对象。

接着会调用 ServletInvocableHandlerMethod#setHandlerMethodArgumentResolvers(),ServletInvocableHandlerMethod#setHandlerMethodReturnValueHandlers() 等方法,这些方法都是用来设置核心的扩展属性,用于解析请求参数(HandlerMethodArgumentResolver),返回值处理(HandlerMethodReturnValueHandler)等,我们前面的辅助类中有相应的实现类。

ServletInvocableHandlerMethod#invokeAndHandle()

ServletInvocableHandlerMethod 对象初始化完成之后,就会执行其 invokeAndHandle() 方法,来调用真正的业务处理代码,并处理返回结果。

java 复制代码
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

    // 执行业务调用
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	... ... 
	try {
        // 返回值处理
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	... ...
}
invokeForRequest()
less 复制代码
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {

    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    ... ...
    return doInvoke(args);
}

在 invokeForRequest() 方法中将先调用 getMethodArgumentValues() 方法,来根据请求及扩展点(HandlerMethodArgumentResolver、PropertyEditorSupport)来解析方法的输入参数。

ini 复制代码
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	MethodParameter[] parameters = getMethodParameters();
	... ...
	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
		MethodParameter parameter = parameters[i];
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
        // 判断是否可以解析,并且代用 Resolver 去解析
		if (!this.resolvers.supportsParameter(parameter)) {
			throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
		}
		try {
			args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		... ...
	}
	return args;
}

getMethodArgumentValues() 中将判断输入的参数是否可以解析,然后调用 HandlerMethodArgumentResolverComposite#resolveArgument() 方法来解析参数。

HandlerMethodArgumentResolverComposite 是一个组合类,里面包含了系统中所有注册过的 HandlerMethodArgumentResolver 对象,当然也包含我们自定义的 HandlerMethodArgumentResolverTest。

调用方法的时候还会将 WebDataBinderFactory 作为参数传入,在 RequestParamMethodArgumentResolver 中,将使用 WebDataBinderFactory 做相应类型的参数解析。

如果是 @RequestBody 注解的参数将调用 RequestResponseBodyMethodProcessor 进行处理,RequestResponseBodyMethodProcessor 类同时实现了 HandlerMethodArgumentResolver,HandlerMethodReturnValueHandler,可以同时对 "Body" 类型的请求参数、返回结果进行处理。RequestResponseBodyMethodProcessor 处理请求参数的时候,将调用 RequestBodyAdvice 扩展点,支持对输入 @RequestBody 的前置、后置、空值处理。

在获得了最终的方法执行参数后,就可以调用实际的业务逻辑处理方法了,即 doInvoke()。

scss 复制代码
protected Object doInvoke(Object... args) throws Exception {
	ReflectionUtils.makeAccessible(getBridgedMethod());
	try {
		return getBridgedMethod().invoke(getBean(), args);
	}
	... ...
}

doInvoke() 方法很简单,就是通过反射调用了实际的业务逻辑处理方法,获得返回值之后就可以返回了。

HandlerMethodReturnValueHandlerComposite#handleReturnValue() 下面就是处理返回值的操作了,HandlerMethodReturnValueHandlerComposite 看名字也知道这也是一个组合类,提供了一个统一的对外接口。里面会根据返回类型,获取合适的 HandlerMethodReturnValueHandler 进行处理。

less 复制代码
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

因为我们使用的是 @ResponseBody 注解,所以将选择 RequestResponseBodyMethodProcessor 进行处理。在 RequestResponseBodyMethodProcessor 的 handleReturnValue() 方法中,将执行 ModelAndViewContainer#setRequestHandled(true); 标记 Request 已经被处理过了。继续往下将执行 RequestResponseBodyMethodProcessor#writeWithMessageConverters() 方法。

ini 复制代码
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
		ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
		throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

	Object body;
	Class<?> valueType;
	Type targetType;

	if (value instanceof CharSequence) {
		... ...
	}
	else {
        // 获得返回类型
		body = value;
		valueType = getReturnValueType(body, returnType);
		targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
	}

	... ...

	MediaType selectedMediaType = null;
	MediaType contentType = outputMessage.getHeaders().getContentType();
	boolean isContentTypePreset = contentType != null && contentType.isConcrete();
	if (isContentTypePreset) {
		... ...
	}
	else {
        // 判断支持的 MediaType,会综合 @RequestMapping 中的 consumes,produces 属性判断
		HttpServletRequest request = inputMessage.getServletRequest();
		List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
		List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
		... ...
		List<MediaType> mediaTypesToUse = new ArrayList<>();
		for (MediaType requestedType : acceptableTypes) {
			for (MediaType producibleType : producibleTypes) {
				if (requestedType.isCompatibleWith(producibleType)) {
					mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
				}
			}
		}
		... ... 
        // 选取一个最合适的 MediaType
		MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
		for (MediaType mediaType : mediaTypesToUse) {
			if (mediaType.isConcrete()) {
				selectedMediaType = mediaType;
				break;
			}
			... ... 
		}
		... ...
	}

	if (selectedMediaType != null) {
		selectedMediaType = selectedMediaType.removeQualityValue();
        // 遍历 HttpMessageConverter
		for (HttpMessageConverter<?> converter : this.messageConverters) {
			GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
					(GenericHttpMessageConverter<?>) converter : null);
            // 看是否支持当前的返回类型,及 MediaType
			if (genericConverter != null ?
					((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
					converter.canWrite(valueType, selectedMediaType)) {
                // 调用 ResponseBodyAdvice 处理返回信息
				body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
						(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
						inputMessage, outputMessage);
				if (body != null) {
					Object theBody = body;
					LogFormatUtils.traceDebug(logger, traceOn ->
							"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
					addContentDispositionHeader(inputMessage, outputMessage);
					// 调用 Converter 输出返回信息
                    if (genericConverter != null) {
						genericConverter.write(body, targetType, selectedMediaType, outputMessage);
					}
					else {
						((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
					}
				}
				else {
					... ...
				}
				return;
			}
		}
	}
	... ...
}

这段代码比较长,首先会根据返回值及返回类型定义,获取返回值的实际类型。然后会根据 @RequestMapping 注解中的 consumes,produces 属性,综合判断可以支持的 MediaType(Content-Type),并选择一个最合适的 MediaType。

之后会遍历当前 Processor 中注入的 HttpMessageConverter 对象,来选择支持的 HttpMessageConverter 对象。如果没有额外指定这里将选择 MappingJackson2HttpMessageConverter,当然也可以根据需要指定 FastJsonHttpMessageConverter 等 HttpMessageConverter。

在数据写出之前,将使用 ResponseBodyAdvice 做输出前的最终处理。

调用完 ResponseBodyAdvice#beforeBodyWrite() 之后,就会调用 HttpMessageConverter#write() 方法进行数据写出。

less 复制代码
public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,
		HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

    // 初始化 Header 信息
	final HttpHeaders headers = outputMessage.getHeaders();
	addDefaultHeaders(headers, t, contentType);

	if (outputMessage instanceof StreamingHttpOutputMessage) {
		... ...
	}
	else {
        // 写数据
		writeInternal(t, type, outputMessage);
		outputMessage.getBody().flush();
	}
}

在 MappingJackson2HttpMessageConverter#write() 方法中,将首先初始化 HttpHeaders 信息,然后调用 writeInternal() 方法,进行数据写出。writeInternal() 方法就是 MappingJackson2HttpMessageConverter 实现的实际数据输出方法,这里将会把数据序列号,并通过 OutputStream 输出数据。

getModelAndView()

一路 return 之后,将执行到 getModelAndView() 方法。

scss 复制代码
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
		ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

	modelFactory.updateModel(webRequest, mavContainer);
	if (mavContainer.isRequestHandled()) {
		return null;
	}
	ModelMap model = mavContainer.getModel();
	ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
	if (!mavContainer.isViewReference()) {
		mav.setView((View) mavContainer.getView());
	}
	... ...
	return mav;
}

由于 Request 在前面已经处理完了,所以,这里将返回 null。否则会根据 ModelAndViewContainer,组装 ModelAndView 对象。

HandlerExecutionChain#applyPostHandle()

又是一路 return,将回到 DispatchServlet#doDispatch() 方法中,接着往下执行 HandlerExecutionChain#applyPostHandle() 方法,而这个就会调用注册的拦截器 HandlerInterceptor 的 postHandle() 方法。

DispatchServlet#processDispatchResult()

最终将调用 DispatchServlet#processDispatchResult() 方法,这个是整个处理过程的收尾方法了。

less 复制代码
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {

	boolean errorView = false;
	// 如果发生异常,将调用 HandlerExceptionResolver 处理
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}
	
	// 如果 ModelAndView 不为空,将执行 ModelAndView 的渲染
	if (mv != null && !mv.wasCleared()) {
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		... ...
	}
	... ...
    // 调用 HandlerInterceptor 的 afterCompletion() 方法
	if (mappedHandler != null) {
		// Exception (if any) is already handled..
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

在 DispatchServlet#processDispatchResult() 方法中,将首先判断处理过程中是否发生异常,如果是,将调用注册的 HandlerExceptionResolver#resolveException() 方法来处理异常。

之后如果 ModelAndView 不为空,将调用 render() 方法来执行视图的渲染。在 render() 方法中首先根据注册的 ViewResolver 来解析获得 View 对象,然后调用 View#render() 方法进行最终的渲染。

如果 ModelAndView 为空,比如我们采用 @ResponseBody 注解,在之前已经处理过返回结果,那么这里就不会再做视图的渲染工作。

无论 ModelAndView 是否为空,最后都会调用 HandlerExecutionChain#triggerAfterCompletion() 方法,也就是会调用 HandlerInterceptor#afterCompletion() ,执行请求最后的拦截器扩展点。

相关推荐
F-2H1 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
苹果酱05671 小时前
「Mysql优化大师一」mysql服务性能剖析工具
java·vue.js·spring boot·mysql·课程设计
武昌库里写JAVA1 小时前
【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等
spring boot·spring·毕业设计·layui·课程设计
_oP_i2 小时前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx2 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康2 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘3 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意4 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上4 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html