Spring MVC 生命周期

說到 Java 開發(fā),現(xiàn)在最流行的框架是什么呢?90% 以上的程序員應(yīng)該會(huì)說是 Spring,而作為 Spring Web 開發(fā)的利器 Spring MVC,更是各位 Java Web 開發(fā)者的心頭好。所以為了能更好、更簡單地開發(fā)一個(gè) Web 項(xiàng)目,了解下 Spring MVC 的底層邏輯是很有必要的,這將幫助我們了解 Spring MVC 提供的各種擴(kuò)展點(diǎn),用更加優(yōu)雅的方式來實(shí)現(xiàn)我們的項(xiàng)目。

整體邏輯

spring mvc處理過程

Spring MVC 的整體處理過程如上圖所示,調(diào)用鏈還是比較清晰。

  1. 當(dāng)請求過來之后,DispatcherServlet 通過 HandlerMapping 獲取一個(gè)合適的 Handler 來處理請求,這里將獲得 HandlerMethod 對象(Controller + Method 封裝),并生成 HandlerExecutionChain 對象
  2. 依據(jù) HandlerMethod ,遍歷 DispatcherServlet 中注入的 HandlerAdapter,獲的合適的 HandlerAdapter 對象
  3. 調(diào)用 HandlerAdapter 對象的 handler() 方法進(jìn)行實(shí)際的業(yè)務(wù)處理,HandlerAdapter 對象中,主要依靠 ServletInvocableHandlerMethod 對象來處理參數(shù)的解析、業(yè)務(wù)調(diào)用、返回值的處理等
  4. HandlerAdapter 處理完之后,將返回 ModelAndView 對象
  5. 如果過程中發(fā)生異常將調(diào)用 HandlerExceptionResolver 處理異常
  6. 使用合適的 ViewResolver 解析 View,并使用 View 進(jìn)行結(jié)果渲染

輔助類及入口

下面我們一起通過源碼來看下上面的過程,源碼版本基于“spring-webmvc-5.2.8.RELEASE”。

輔助類

下面是我讀源碼過程中用到的相關(guān)類。

/**
 * Spring MVC 生命周期示例
 * @author 魚蠻 on 2019/2/15
 **/
@Slf4j
@RestController
public class SpringMvcLifeCycleTestController {

    /**
     * 用于演示 Spring Mvc 的生命周期
     *
     * @param date       PropertyEditorSupport 處理結(jié)果
     * @param mvcRequest HandlerMethodArgumentResolver 處理結(jié)果
     * @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;
        }
    }
}
/**
 * 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");
    }
}
/**
 * PropertyEditorSupport 使用示例
 *
 * @author 魚蠻 on 2019/2/15
 **/
@ControllerAdvice
public class EditorTest {

    /**
     * 注冊 {@link Date} 類型解析.
     *
     * @param binder    數(shù)據(jù)綁定器
     * @param request   request
     */
    @InitBinder
    public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(Date.class, new DateEditor());

        // 統(tǒng)一去除String參數(shù)中的前后空格
        StringTrimmerEditor stringTrimmer = new StringTrimmerEditor(true);
        binder.registerCustomEditor(String.class, stringTrimmer);
    }

    /**
     * 日期字段自動(dòng)轉(zhuǎn) java.util.Date
     **/
    @Slf4j
    public class DateEditor extends PropertyEditorSupport {

        /** 常規(guī)日期時(shí)間格式 */
        public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        /** 精簡日期時(shí)間格式 */
        public static final String SIMPLE_DATETIME_PATTERN = "yyyyMMddHHmmss";

        /** 常規(guī)日期格式 */
        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);
        }
    }
}
/**
 *  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;
    }
}
/**
 * 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()

源碼的入口也很好找,因?yàn)?Spring MVC 是基于 Servlet 規(guī)范的,所以 DispartchServlet 繼承自 HttpServlet,通過的 HttpServelt 的入口很容易找到最終的調(diào)用入口是 DispatchServlet#doDispatch() 。這個(gè)方法就是整個(gè) Spring MVC 的核心處理過程。

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());

            ... ...

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

            // 實(shí)際的請求處理
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            ... ...
                // 調(diào)用 HandlerInterceptor 的 postHandler() 方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            ... ...
            }
        // 執(zhí)行 ModelAndView 的解析、渲染
        // 調(diào)用 HandlerInterceptor 的 afterCompletion() 方法
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    ... ...
}

過程解讀

DispatchServlet#getHandler()

首先是調(diào)用 DispatchServlet#getHandler() 方法來獲得 HandlerExecutionChain 對象。這個(gè)其實(shí)主要就是通過遍歷已經(jīng)注入的類型為 List<HandlerMapping> 的 handlerMappings 屬性,來找一個(gè)合適的 HandlerMapping,再通過 HandlerMapping 來處理,對普通的請求基本都適用 RequestMappingInfoHandlerMapping。

RequestMappingInfoHandlerMapping#getHandler()

getHandlerInternal()

RequestMappingInfoHandlerMapping 中將首先調(diào)用 getHandlerInternal() 方法,通過請求中的 URL 地址,獲得相應(yīng)的 HandlerMethod 對象,而 HandlerMethod 里面包裝的就是實(shí)際的業(yè)務(wù)邏輯處理類 Controller 及 Method 等信息。

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根據(jù)請求的 URL 去找最合適的 HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

getHandlerExecutionChain()

這一步將獲得一個(gè) HandlerExecutionChain 對象,會(huì)將上一步中獲得的 HandlerMethod 對象作為屬性注入其中。并且根據(jù)請求 URL 匹配 HandlerInterceptor(攔截器),組裝到 HandlerExecutionChain 對象中,后面都是使用 HandlerExecutionChain 來間接觸發(fā) HandlerInterceptor。

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;
            // 根據(jù)請求的 URL 獲取匹配的 HandlerInterceptor,加入到 chain 中
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

DispatchServlet#getHandlerAdapter()

這一步其實(shí)很簡單,就是通過上面獲取的 HandlerExecutionChain 對象中的 handler 屬性(HandlerMethod 對象)來獲取支持的 HandlerAdapter 對象。

這里最終獲得的 HandlerAdapter 對象是:RequestMappingHandlerAdapter。

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

HandlerExecutionChain#applyPreHandle()

在調(diào)用實(shí)際業(yè)務(wù)處理代碼之前,會(huì)先執(zhí)行 HandlerExecutionChain#applyPreHandle() 方法,而這個(gè)就會(huì)調(diào)用上面匹配的攔截器 HandlerInterceptor 中的 preHandle() 方法。如果返回值不為 true,將結(jié)束請求的處理。

RequestMappingHandlerAdapter#handle()

獲得了 RequestMappingHandlerAdapter 對象之后,就需要調(diào) RequestMappingHandlerAdapter#handle() 方法進(jìn)行實(shí)際的業(yè)務(wù)調(diào)用,及相關(guān)處理。這個(gè)方法只是一個(gè)對外接口方法,里面將調(diào)用真正的實(shí)現(xiàn)方法 handleInternal(),繼續(xù)往下,將調(diào)用核心的邏輯處理方法 invokeHandlerMethod()。

invokeHandlerMethod()

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        ... ...
        // 初始化 ServletInvocableHandlerMethod 對象
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 核心屬性設(shè)置 HandlerMethodArgumentResolver
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 核心屬性設(shè)置 HandlerMethodReturnValueHandler
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 核心屬性用于參數(shù)解析,PropertyEditorSupport
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        ... ...
        // 執(zhí)行業(yè)務(wù)邏輯方法,并且處理結(jié)果
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        ... ...

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

在 invokeHandlerMethod() 方法中,首先會(huì)調(diào)用 createInvocableHandlerMethod() 方法,創(chuàng)建 ServletInvocableHandlerMethod 對象。

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;
}

一路追蹤下去,會(huì)發(fā)現(xiàn) ServletInvocableHandlerMethod 繼承自 HandlerMethod,創(chuàng)建的時(shí)候會(huì)將上面獲得的 HandlerMethod 對象傳入,讀取核心屬性來創(chuàng)建 ServletInvocableHandlerMethod 對象。

接著會(huì)調(diào)用 ServletInvocableHandlerMethod#setHandlerMethodArgumentResolvers(),ServletInvocableHandlerMethod#setHandlerMethodReturnValueHandlers() 等方法,這些方法都是用來設(shè)置核心的擴(kuò)展屬性,用于解析請求參數(shù)(HandlerMethodArgumentResolver),返回值處理(HandlerMethodReturnValueHandler)等,我們前面的輔助類中有相應(yīng)的實(shí)現(xiàn)類。

ServletInvocableHandlerMethod#invokeAndHandle()

ServletInvocableHandlerMethod 對象初始化完成之后,就會(huì)執(zhí)行其 invokeAndHandle() 方法,來調(diào)用真正的業(yè)務(wù)處理代碼,并處理返回結(jié)果。

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {

    // 執(zhí)行業(yè)務(wù)調(diào)用
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

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

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

在 invokeForRequest() 方法中將先調(diào)用 getMethodArgumentValues() 方法,來根據(jù)請求及擴(kuò)展點(diǎn)(HandlerMethodArgumentResolver、PropertyEditorSupport)來解析方法的輸入?yún)?shù)。

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() 中將判斷輸入的參數(shù)是否可以解析,然后調(diào)用 HandlerMethodArgumentResolverComposite#resolveArgument() 方法來解析參數(shù)。

HandlerMethodArgumentResolverComposite 是一個(gè)組合類,里面包含了系統(tǒng)中所有注冊過的 HandlerMethodArgumentResolver 對象,當(dāng)然也包含我們自定義的 HandlerMethodArgumentResolverTest。

調(diào)用方法的時(shí)候還會(huì)將 WebDataBinderFactory 作為參數(shù)傳入,在 RequestParamMethodArgumentResolver 中,將使用 WebDataBinderFactory 做相應(yīng)類型的參數(shù)解析。

如果是 @RequestBody 注解的參數(shù)將調(diào)用 RequestResponseBodyMethodProcessor 進(jìn)行處理,RequestResponseBodyMethodProcessor 類同時(shí)實(shí)現(xiàn)了 HandlerMethodArgumentResolver,HandlerMethodReturnValueHandler,可以同時(shí)對 “Body” 類型的請求參數(shù)、返回結(jié)果進(jìn)行處理。RequestResponseBodyMethodProcessor 處理請求參數(shù)的時(shí)候,將調(diào)用 RequestBodyAdvice 擴(kuò)展點(diǎn),支持對輸入 @RequestBody 的前置、后置、空值處理。

在獲得了最終的方法執(zhí)行參數(shù)后,就可以調(diào)用實(shí)際的業(yè)務(wù)邏輯處理方法了,即 doInvoke()。

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

doInvoke() 方法很簡單,就是通過反射調(diào)用了實(shí)際的業(yè)務(wù)邏輯處理方法,獲得返回值之后就可以返回了。

HandlerMethodReturnValueHandlerComposite#handleReturnValue()
下面就是處理返回值的操作了,HandlerMethodReturnValueHandlerComposite 看名字也知道這也是一個(gè)組合類,提供了一個(gè)統(tǒng)一的對外接口。里面會(huì)根據(jù)返回類型,獲取合適的 HandlerMethodReturnValueHandler 進(jìn)行處理。

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);
}

因?yàn)槲覀兪褂玫氖?@ResponseBody 注解,所以將選擇 RequestResponseBodyMethodProcessor 進(jìn)行處理。在 RequestResponseBodyMethodProcessor 的 handleReturnValue() 方法中,將執(zhí)行 ModelAndViewContainer#setRequestHandled(true); 標(biāo)記 Request 已經(jīng)被處理過了。繼續(xù)往下將執(zhí)行 RequestResponseBodyMethodProcessor#writeWithMessageConverters() 方法。

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,會(huì)綜合 @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));
                }
            }
        }
        ... ... 
        // 選取一個(gè)最合適的 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);
            // 看是否支持當(dāng)前的返回類型,及 MediaType
            if (genericConverter != null ?
                    ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
                    converter.canWrite(valueType, selectedMediaType)) {
                // 調(diào)用 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);
                    // 調(diào)用 Converter 輸出返回信息
                    if (genericConverter != null) {
                        genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                    }
                    else {
                        ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                    }
                }
                else {
                    ... ...
                }
                return;
            }
        }
    }
    ... ...
}

這段代碼比較長,首先會(huì)根據(jù)返回值及返回類型定義,獲取返回值的實(shí)際類型。然后會(huì)根據(jù) @RequestMapping 注解中的 consumes,produces 屬性,綜合判斷可以支持的 MediaType(Content-Type),并選擇一個(gè)最合適的 MediaType。

之后會(huì)遍歷當(dāng)前 Processor 中注入的 HttpMessageConverter 對象,來選擇支持的 HttpMessageConverter 對象。如果沒有額外指定這里將選擇 MappingJackson2HttpMessageConverter,當(dāng)然也可以根據(jù)需要指定 FastJsonHttpMessageConverter 等 HttpMessageConverter。

在數(shù)據(jù)寫出之前,將使用 ResponseBodyAdvice 做輸出前的最終處理。

調(diào)用完 ResponseBodyAdvice#beforeBodyWrite() 之后,就會(huì)調(diào)用 HttpMessageConverter#write() 方法進(jìn)行數(shù)據(jù)寫出。

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 {
        // 寫數(shù)據(jù)
        writeInternal(t, type, outputMessage);
        outputMessage.getBody().flush();
    }
}

在 MappingJackson2HttpMessageConverter#write() 方法中,將首先初始化 HttpHeaders 信息,然后調(diào)用 writeInternal() 方法,進(jìn)行數(shù)據(jù)寫出。writeInternal() 方法就是 MappingJackson2HttpMessageConverter 實(shí)現(xiàn)的實(shí)際數(shù)據(jù)輸出方法,這里將會(huì)把數(shù)據(jù)序列號(hào),并通過 OutputStream 輸出數(shù)據(jù)。

getModelAndView()

一路 return 之后,將執(zhí)行到 getModelAndView() 方法。

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 在前面已經(jīng)處理完了,所以,這里將返回 null。否則會(huì)根據(jù) ModelAndViewContainer,組裝 ModelAndView 對象。

HandlerExecutionChain#applyPostHandle()

又是一路 return,將回到 DispatchServlet#doDispatch() 方法中,接著往下執(zhí)行 HandlerExecutionChain#applyPostHandle() 方法,而這個(gè)就會(huì)調(diào)用注冊的攔截器 HandlerInterceptor 的 postHandle() 方法。

DispatchServlet#processDispatchResult()

最終將調(diào)用 DispatchServlet#processDispatchResult() 方法,這個(gè)是整個(gè)處理過程的收尾方法了。

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

    boolean errorView = false;
    // 如果發(fā)生異常,將調(diào)用 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 不為空,將執(zhí)行 ModelAndView 的渲染
    if (mv != null && !mv.wasCleared()) {
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        ... ...
    }
    ... ...
    // 調(diào)用 HandlerInterceptor 的 afterCompletion() 方法
    if (mappedHandler != null) {
        // Exception (if any) is already handled..
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

在 DispatchServlet#processDispatchResult() 方法中,將首先判斷處理過程中是否發(fā)生異常,如果是,將調(diào)用注冊的 HandlerExceptionResolver#resolveException() 方法來處理異常。

之后如果 ModelAndView 不為空,將調(diào)用 render() 方法來執(zhí)行視圖的渲染。在 render() 方法中首先根據(jù)注冊的 ViewResolver 來解析獲得 View 對象,然后調(diào)用 View#render() 方法進(jìn)行最終的渲染。

如果 ModelAndView 為空,比如我們采用 @ResponseBody 注解,在之前已經(jīng)處理過返回結(jié)果,那么這里就不會(huì)再做視圖的渲染工作。

無論 ModelAndView 是否為空,最后都會(huì)調(diào)用 HandlerExecutionChain#triggerAfterCompletion() 方法,也就是會(huì)調(diào)用 HandlerInterceptor#afterCompletion() ,執(zhí)行請求最后的攔截器擴(kuò)展點(diǎn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容