为了账号安全,请及时绑定邮箱和手机立即绑定

springMVC 如何执行Handler

标签:
Java


流程回顾

  1. 根据请求路径和已经加载的HandlerMapping集合,找到HandlerExecutionChain【包含了Handler和interceptors集合】,具体可参考  RequestMappingHandlerMapping 详解

  2. 根据HandlerExecutionChain中的Handler类型,找到HandlerAdapter ,具体可参考 HandlerAdapter

  3. 根据HandlerExecutionChain携带的拦截器【也就是mvc:interceptors标签配置的拦截器】,在执行Handler处理请求前,处理请求后后,完成后开始执行对应的拦截器,具体可以参考 springMVC 拦截器

  4. 最后根据HandlerAdapter,开始执行其ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)方法,获取ModelAndView,最后根据ModelAndView来渲染View视图。

数据绑定

在我们真正执行Controller中的Action的方法之前,需要把HttpServletRequest中的请求数据【不论是query string或者是form 表单】映射到对应的方法的参数上,这个过程我们称之为数据绑定,数据绑定的过程包含类型转换和数据值绑定两个方面

因为最终的Handler的方法是由HandlerAdapter执行的,所以在真正执行方法前,数据绑定的前置准备工作是由HandlerAdapter来完成的,通过源码分析,我们可以知道数据绑定是由HandlerMethodArgumentResolver来完成的【我们称之为参数解析器】,而Handler执行完成后的returnValue的处理则是由HandlerMethodReturnValueHandler来处理【我们称之为返回值处理器】
按照这种模式,那么每个HandlerAdapter初始化完成后应该是需要先加载一些参数解析器和返回值处理器的,我们看下RequestMappingHandlerAdapter的初始化过程如下

public void afterPropertiesSet() {
        // Do this first, it may add ResponseBody advice beans
        initControllerAdviceCache();
        if (this.argumentResolvers == null) {
            //加载默认的参数初始化器
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            //加载默认的返回值解析器
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
        // Annotation-based argument resolution
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());
        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        resolvers.add(new ModelMethodProcessor());
        resolvers.add(new MapMethodProcessor());
        resolvers.add(new ErrorsMethodArgumentResolver());
        resolvers.add(new SessionStatusMethodArgumentResolver());
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }
        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
        return resolvers;
    }

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
        // Single-purpose return value types
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        handlers.add(new ModelMethodProcessor());
        handlers.add(new ViewMethodReturnValueHandler());
        handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
                this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
        handlers.add(new StreamingResponseBodyReturnValueHandler());
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));
        handlers.add(new HttpHeadersReturnValueHandler());
        handlers.add(new CallableMethodReturnValueHandler());
        handlers.add(new DeferredResultMethodReturnValueHandler());
        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
        // Annotation-based return value types
        handlers.add(new ModelAttributeMethodProcessor(false));
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));
        // Multi-purpose return value types
        handlers.add(new ViewNameMethodReturnValueHandler());
        handlers.add(new MapMethodProcessor());
        // Custom return value types
        if (getCustomReturnValueHandlers() != null) {
            handlers.addAll(getCustomReturnValueHandlers());
        }
        // Catch-all
        if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
        }
        else {
            handlers.add(new ModelAttributeMethodProcessor(true));
        }
        return handlers;
    }

我们看下InvocableHandlerMethod.invokeForRequest方法, Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs)就是数据绑定的过程,根据请求ServletRequest对象和HanderMethod中需要的参数,将两者做一个映射,最终得到一个参数列表,然后开始执行doInvoke

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
                //这里便是数据绑定的全过程
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        Object returnValue = doInvoke(args);
        return returnValue;
    }

private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        MethodParameter[] parameters = getMethodParameters();
        Object[] args = new Object[parameters.length];
                /*这里遍历所有的参数【每个参数用一个MethodParameter对象标识】,
                然后从HandlerMethodArgumentResolverComposite中查询合适的 
                HandlerMethodArgumentResolver来处理这个参数,所以如果我们希望把HttpServletRequest中的参数解析到我们自定义的参数中,可以通过自定义HandlerMethodArgumentResolver来完成
*/
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = resolveProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (this.argumentResolvers.supportsParameter(parameter)) {
                try {
                    args[i] = this.argumentResolvers.resolveArgument(
                            parameter, mavContainer, request, this.dataBinderFactory);
                    continue;
                }
            }
        }
        return args;
    }

更加详细的数据绑定可以参考数据绑定系列

spring mvc 中的数据绑定【基础篇】
spring mvc 中的数据绑定【进阶篇】
spring mvc 中的数据绑定【实战篇】

开始执行

当数据绑定完成之后,HandlerAdapter则是直接执行对应的HanderMethod,获取返回值

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
                //这里便是数据绑定的全过程
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        //直接执行Handler,这里其实就是直接执行Controler中的具体方法
        Object returnValue = doInvoke(args);
        return returnValue;
    }

数据输出

执行完HandlerMethod后,回返回一个returnValue,接着会调用returnValueHandlers.handleReturnValue来处理返回值,根据返回值的类型做出不同的处理,处理流程如下

  1. 根据返回值类型和返回值来选择合适的HandlerMethodReturnValueHandler 来处理返回值

  2. 根据不同的返回值,会有不同处理,比如是ModelAndView 则调用ModelAndViewMethodReturnValueHandler这个HandlerMethodReturnValueHandler来处理,会直接根据物理视图来做view的渲染工作

  3. 如果是API接口,需要返回JSON的话,那么此时如果加上了@ResponseBody注解的话【这个开发api接口的应该很熟悉】,会由RequestResponseBodyMethodProcessor来处理,会根据消息格式选择不同的HttpMessageConverter来处理,并标记为请求已处理

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        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 {
//根据returnValue 的值,调用handleReturnValue来处理不同类型的返回值
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
    }

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


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
5
获赞与收藏
27

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消