Back to Javatutorial

请求执行流程(二)之执行Handler方法

docs/Spring全家桶/SpringMVC源码分析/请求执行流程(二)之执行Handler方法.md

1.0.020.7 KB
Original Source

springmvc ִĵڶƪ£һƪУǷ DispatcherServlet#doDispatch ִܽзΪ²裺

  1. ȡӦ HandlerExecutionChain, ȡ HandlerExecutionChain аشController еķһ HandlerInterceptor
  2. ȡӦ handlerAdapterö handler(xxx)
  3. ִ spring HandlerInterceptor#preHandle
  4. Ҳͨȡ handlerAdapter handle(xxx)
  5. ִ spring HandlerInterceptor#postHandle
  6. ؽȾͼԼִ spring HandlerInterceptor#afterCompletion

ţǼ HandlerExecutionChain ĻȡԼ handlerAdapter ĻȡϻأĽIJ衣

5. ִ spring HandlerInterceptor#preHandle

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    // 3\. spring,  HandlerInterceptor#preHandle 
    // mappedHandlerǵ1ȡHandlerExecutionChain
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }
    ...
}

mappedHandlerǵ 1 ȡ HandlerExecutionChain HandlerExecutionChain#applyPreHandle

HandlerExecutionChain#applyPreHandle

/**
 * ִ HandlerInterceptor#preHandle 
 */
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) 
        throws Exception {
    // ȡе
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        // ִ preHandle 
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                // ʧˣִ HandlerInterceptor#afterCompletion 
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}

/**
 * ִ HandlerInterceptor#afterCompletion 
 * Ϊ˱֤HandlerInterceptor#afterCompletionִУ
 * ķῴڶõ
 */
void triggerAfterCompletion(HttpServletRequest request, 
        HttpServletResponse response, @Nullable Exception ex) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        // ִ HandlerInterceptor#afterCompletion 
        for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}

һ HandlerExecutionChain

HandlerInterceptor handler ɶ

handler HandlerMethodϢͦḻģ bean/beanFactory/method⼸ԣǿԶиֲ

6. ִУAbstractHandlerMethodAdapter#handle

ٻص DispatcherServlet#doDispatchִ HandlerInterceptor#preHandle 󣬾еͷϷhandler ִУҲ controller Уurl ӦķִУ

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    // 4\. ͨȡhandlerAdapterhandle
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    ...
}

һ·ȥ RequestMappingHandlerAdapter#invokeHandlerMethod

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // װrequesrequest
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // ȡ @InitBinder עķ
        // ǰcontroller @ControllerAdvice ע @InitBinder עķ
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // ȡ @ModelAttribute עķ
        // ǰcontroller @ControllerAdvice ע @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);
        // ModelAndView
        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);
        }
        // ִControllerķص㣩
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        // ؽ
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

е㳤ص㷽ֻһУinvocableMethod.invokeAndHandle(webRequest, mavContainer);ǰIJִֶǰ׼ȡ @InitBinder עķȡ @ModelAttribute עķ׼ webRequestrequest response ) mavContainer(ModelAndView װ) ȡֱӽ invocableMethod.invokeAndHandleִеģ

ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {
    // ִhandler
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    //  RequestHandled ֵspringmvcݸֵжҪҪת
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null 
                || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            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 {
        // ؽ
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        throw ex;
    }
}

﷽ǵ invokeForRequest ִзȻٸݷķֵ mavContainer RequestHandled ֵؽ invokeForRequest

InvocableHandlerMethod#invokeForRequest

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
        Object... providedArgs) throws Exception {
    // 
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    // ÷
    return doInvoke(args);
}

Ǵ˲Ȼʹ÷зáʵϣִУĵľDzˣ controller handler Уǿָ

// ֱӴ
@RequestMapping("xxx")
public Object test(String name) {
    ...
}

// ڲϱ@RequestParam@RequestHeaderע
@RequestMapping("xxx")
public Object test(@RequestParam("name") String name, 
                   @RequestHeader("uid") String uid) {
    ...
}

// IJװΪ
@RequestMapping("xxx")
public Object test(User user) {
    ...
}

// ķʹform(Ҳk1=v1&2=v2&...ķ)
// ʹ RequestBody ʽΣݷϢ
@RequestMapping("xxx")
public Object test(@RequestBody User user) {
    ...
}

...

ǰ淶ʱspringmvc springmvc һġ

InvocableHandlerMethod#getMethodArgumentValues

InvocableHandlerMethod#getMethodArgumentValues

protected Object[] getMethodArgumentValues(NativeWebRequest request, 
        @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // ȡвԼΪ÷ȡhandlerȻװΪ MethodParameter
    MethodParameter[] parameters = getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    }
    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;
        }
        // жǷвֵ֧ǰĽ
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            // 
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, 
                    this.dataBinderFactory);
        }
        catch (Exception ex) {
            throw ex;
        }
    }
    return args;
}

Ȼȡ handler IJ (ԼΪ÷ȡ handler ȻװΪ MethodParameter)ȻЩʱõҪķresolvers.supportsParameter(...) resolvers.resolveArgument(...)յõķ HandlerMethodArgumentResolverComposite У

HandlerMethodArgumentResolverComposite

@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainermavContainer,
        NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    // ȡһ
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException(...);
    }
    //  HandlerMethodArgumentResolver#resolveArgument 
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        // еĽ
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            // ҵһ
            //  HandlerMethodArgumentResolver#supportsParameter 
            if (resolver.supportsParameter(parameter)) {
                result = resolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}

ҪDZȻ HandlerMethodArgumentResolver#supportsParameter HandlerMethodArgumentResolver#resolveArgument IJHandlerMethodArgumentResolver Ǹӿڣ

public interface HandlerMethodArgumentResolver {
    /**
     * ǰǷִ֧ǰ
     */
    boolean supportsParameter(MethodParameter parameter);

    /**
     * Ľ
     */
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

IJˡ springmvc Уṩ˶ֲأ˵ĵԣֶ 26

Щİ£springmvc ֲֶ֧շʽڲƱȽϸӣ漰ִηʽIJչۣȤСвĵ

ִ handler

󣬾Ϳʼִ handler ˡǻص InvocableHandlerMethod#invokeForRequest

InvocableHandlerMethod#invokeForRequest

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
        Object... providedArgs) throws Exception {
    // 
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    // ÷
    return doInvoke(args);
}

doInvoke

@Nullable
protected Object doInvoke(Object... args) throws Exception {
    // ʹ÷ִз
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // Ƿ
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (...) {
        ...
    }
}

ܼ򵥣÷зִеģͲˡ

ز

ǻص ServletInvocableHandlerMethod#invokeAndHandle

ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {
    // ִhandle
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    ...
    try {
        // ؽ
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        throw ex;
    }
}

귽ִк󣬽žʹؽ

HandlerMethodReturnValueHandlerComposite#handleReturnValue

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
        ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    // ݷһʵhandler
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException(...);
    }
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameterreturnType) {
    boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    // жǷܴǰ
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
        if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
            continue;
        }
        if (handler.supportsReturnType(returnType)) {
            return handler;
        }
    }
    return null;
}

ȡ ReturnValueHandler ·ǰȡ ArgumentResolver ·޼ReturnValueHandler HandlerMethodReturnValueHandlerHandlerMethodReturnValueHandler £

public interface HandlerMethodReturnValueHandler {

    /**
     * жϵǰReturnValueHandlerܷreturnType
     */
    boolean supportsReturnType(MethodParameter returnType);

    /**
     * Ĵ߼
     */
    void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

ͬǰһӿҲ

  • boolean supportsReturnType(xxx)жϵǰ ReturnValueHandler ܷ returnType
  • void handleReturnValue(xxx)Ĵ߼

ͬأspringmvc Ҳṩ˷dzʵز

ڲķأһ򵥵ʾ

ֵʱ

@Controller
@RequestMapping("/xxx")
public class XxxController {

    @RequestMapping("/index")
    public String index() {
        return "index";
    }
}

صҳĽһͼӦ HandlerMethodReturnValueHandler Ϊ ViewNameMethodReturnValueHandler

public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Nullable
    private String[] redirectPatterns;

    // ʡ redirectPatterns settergetter
    ...

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        Class<?> paramType = returnType.getParameterType();
        // ִ֧ķֵֵͣΪvoidΪַ
        return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
    }

    /**
     * Ĵ߼
     */
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        if (returnValue instanceof CharSequence) {
            // viewName Ƿֵ
            String viewName = returnValue.toString();
            mavContainer.setViewName(viewName);
            if (isRedirectViewName(viewName)) {
                // ǷҪת
                mavContainer.setRedirectModelScenario(true);
            }
        }
        else if (returnValue != null) {
            throw new UnsupportedOperationException(...);
        }
    }

    /**
     * жǷҪת
     */
    protected boolean isRedirectViewName(String viewName) {
        // this.redirectPatterns ĬΪnullе setter 
        return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName) 
            // ƥ redirect: ͷҲ˵Ƿ "redirect:index"ͱýҪת
            || viewName.startsWith("redirect:"));
    }

}

Ƚϼ򵥣ؼڴעͣͲ˵ˡֵһǣ handleReturnValue(xxx) Уspringmvc صַΪ viewName Ҫע£ڴͼʱ viewName õӦ View

ȡ ModelAndView

ǻص RequestMappingHandlerAdapter#invokeHandlerMethod

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        ...
        // ִControllerķ
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        // ִнõ ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

ִ invocableMethod.invokeAndHandle(webRequest, mavContainer) žǴִнõ ModelAndView ˣ RequestMappingHandlerAdapter#getModelAndView

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
        ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    //  ModelFactoryǰȡ @ModelAttribute עķ
    modelFactory.updateModel(webRequest, mavContainer);
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    ModelMap model = mavContainer.getModel();
    // ͼ󣬰mavContainer.getViewName()뵽ModelAndViewĹ췽
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), 
            model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }
    // ض
    if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
    }
    return mav;
}

ԿModelAndView Ǵǰִн viewName õġ

ˣAbstractHandlerMethodAdapter#handle ִϡ

7. ִHandlerInterceptor#postHandle

ٻص DispatcherServlet#doDispatch

DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...

    try {
        ...
        try {
            ...
            // 4.ͨȡhandlerAdapterhandle
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // 5.ûзͼʹĬϵ
            applyDefaultViewName(processedRequest, mv);
            // 6\. ִ HandlerInterceptor#postHandle 
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (...) {
            ...
        }
        // 7\. ؽִ HandlerInterceptor.afterCompletion
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (...) {
        ...
    }
}

ִ handler 󣬾Ϳʼִ HandlerInterceptor#postHandle ˣ

HandlerExecutionChain#applyPostHandle

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, 
        @NullableModelAndView mv) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        // ִ postHandle(...) 
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}

ͬǰִƣͲˡҪǿǣHandlerInterceptor#postHandle ִʱִ handler ֮ͼ֮ǰˣǿﴦһЩȾ

ƪľȵˣrequest ִеḷ́ƪٷ


ԭӣhttps://my.oschina.net/funcy/blog/4741104 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע