spring-webmvc请求处理流程——返回值处理

spring-webmvc请求处理流程——返回值处理

继上一篇spring-webmvc请求处理流程以后,本篇继续讲解3.2.x版本以后使用的RequestMappingHandlerAdapter,该类替换了AnnotationMethodHandlerAdapter。java

RequestMappingHandlerAdapter

自3.2以后的版本,引入了RequestMappingHandlerAdapter来替换了AnnotationMethodHandlerAdapter的处理。这里也来分析一下这个玩意儿。web

由于也是一个HandlerAdapter,因此,前面的处理流程都是同样的,servlet的getHandlerAdapter这个时候就返回了RequestMappingHandlerAdapter,而不是AnnotationMethodHandlerAdapter了。spring

拿到HandlerAdapter以后,咱们就直接冲ha.handle()方法开始分析吧。json

// RequestMAppingHandlerAdapter.java
protected final ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    //...作一些检查
    return invokeHandleMethod(request, response, handlerMethod);
}

private ModelAndView invokeHandleMethod(HttpServletRequest request,
             HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
	
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    //拿取咱们须要执行的controller的方法
    ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
	// 用于后面构造mv的Container
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
	//...这一段是对异步请求的处理
    //调用controller的方法,并处理mavContainer
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

    if (asyncManager.isConcurrentHandlingStarted()) {
        return null;
    }

    return getModelAndView(mavContainer, modelFactory, webRequest);
}

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
                                     ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

    modelFactory.updateModel(webRequest, mavContainer);
    //判断,若是当前请求已经处理完成,则不进行后续的处理没直接返回null
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    //若是请求还未处理完成,那说明可能有页面须要返回,开始查找,处理并返回mav
    ModelMap model = mavContainer.getModel();
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }
    if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
    }
    return mav;
}

直接跟进去。来到RequestMappingHAndlerAdapter的handleInternal()方法,不要惊慌,按照spring的一向风格,这TM固然不是核心方法,他只是作了一些检查。方法最后调用了invokeHandleMethod()。在该方法中,作了一些所需参数的获取,好比请求的controller层方法,参数。而后调用ServletInvocableHandlerMethod对象invokeAndHandle方法。mvc

调用业务方法,并处理返回值

//ServletInvocableHandlerMethod.java
public final void invokeAndHandle(ServletWebRequest webRequest,
       ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 真正调用controller方法,得到结果
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	//设置响应状态
    setResponseStatus(webRequest);
	//若是返回值为null,则说明该请求不返回任何结果,直接设置mavContainer.setRequestHandled(true)
    //设置为true以后,表示该请求已经处理完,后续再也不处理,后续会提到这个
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(this.responseReason)) {
        mavContainer.setRequestHandled(true);
        return;
    }
	//设置为false,表示当前请求还未处理完成
    mavContainer.setRequestHandled(false);

    try {
        //调用默认的和自定义的全部返回值解析器处理返回结果
        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {//...}
        throw ex;
    }
}

从注释中可于了解到,首先调用业务逻辑得到返回结果,而后对返回值作必定的判断并简单处理。经过returnValueHandlers对象来进一步处理返回结果。这是个HandlerMethodReturnValueHandlerComposite类型的对象,继续跟进。app

public void handleReturnValue(
        Object returnValue, MethodParameter returnType,
        ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
        throws Exception {
	// 得到能够处理返回值的handler,固然也是经过遍历,能够看方法
    HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
    //若是没有合适的返回值处理器,就会报错
    Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
    //使用返回值处理器处理返回结果
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
    //遍历全部handler,包括自定义的
    for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
        //...
        if (returnValueHandler.supportsReturnType(returnType)) {
            //若是该handler可以处理当前返回值,就返回该handler
            return returnValueHandler;
        }
    }
    return null;
}

来,看一下全部的默认注册的处理器。看到了RequestResponseBodyMethodProcessor是否是很亲切呢,对咯,他就是处理@ResponseBody注解的。喜欢的朋友能够去看哈这个类的supportsReturnType()方法就明白了。异步

returnValueHandler

到这里就不继续跟了,咱们熟悉的RequestResponseBodyMethodProcessor处理器处理结果的时候会设置mavContainer.setRequestHandled(true);表示处理已经完毕。async

getModelAndView()

处理完以后,回到RequestMappingHandlerAdapter的invokeHandleMethod()方法。这个方法最终返回了getModelAndView();ide

从该方法中,咱们能够看到,若是当前请求已经处理完成(mavContainer.isRequestHandled()值为true),则不进行后续的处理没直接返回null,不然spring会继续处理当前请求,并试图返回一个ModelAndView。测试

自定义HandlerMethodReturnValueHandler

既然上面提到了自定义的返回值处理器,那这个自定义是在哪里的呢?这个返回值处理器就是在哪里注册的呢?精彩立刻回来!

自定义返回值处理器

返回值处理器须要实现HandlerMethodReturnValueHandler

public class MyCustomReturnValueHandler implements HandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        //判断方法是否包含自定义注解MyResonse或者返回结果是指定的某种类型
        return returnType.getMethodAnnotation(MyResponse.class) != null || ResponseResult.class.isAssignableFrom(returnType.getParameterType());
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 代表该请求已经处理,后面spring不会再处理
        mavContainer.setRequestHandled(true);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(JSON.toJSONString(returnValue));
    }
}

controller,我这里注解和返回值类型都符合上面处理器的要求,事实上只要一种就行了。

@RequestMapping("/testValueHandler")
@MyResponse
public ResponseResult testValueHandler() {
	return new ResponseResult(0,"success");
}

springmvc.xml

<mvc:annotation-driven>
	<mvc:return-value-handlers>
		<bean class="com.wt.test.webmvc.config.MyCustomReturnValueHandler"/>
	</mvc:return-value-handlers>
</mvc:annotation-driven>

自定义返回结果处理器的初始化过程

从xml中能够看到是自定义标签mvc:return-value-handlers,跟踪MvcNamespaceHandler。

// MvcNamespaceHandler.java
public void init() {
    //解析自定义标签的parser
	registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
}

进入AnnotationDrivenBeanDefinitionParser的parse方法,自定义的就是在这里处理的,咱们来看一下。

// AnnotationDrivenBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
	//...
    //获取自定义的返回值处理器
    ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
    //...
    // 定义RequestMappingAdapterHandler
    RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
    //...
    if (returnValueHandlers != null) {
        //设置自定义返回值处理器的属性customReturnValueHandlers
	handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
		}
    //...
    // 将定义的RequestMappingAdapterHandler注册为spring的bean
    parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
    //...
}

// 解析自定义标签return-value-handlers
private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) {
	Element handlersElement = DomUtils.getChildElementByTagName(element, "return-value-handlers");
	if (handlersElement != null) {
		return extractBeanSubElements(handlersElement, parserContext);
	}
	return null;
}

直接看注释了,不解释了。到这里自定义的返回值处理器就已经注册完了,已是spring的一个bean了。如今咱们来看看RequestMappingHandlerAdapter。

这个家伙实现了InitializingBean,咱们来看afterPropertiesSet方法。

public void afterPropertiesSet() {
    //...
    }
    if (this.returnValueHandlers == null) {
        //获取全部的返回值处理器,不要看方法名是getDefaultReturnVanlueHandler,实际上在里面也包含了自定义的处理器
        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
    initControllerAdviceCache();
}

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
    List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
	// 默认的返回值处理器
    // Single-purpose return value types
    handlers.add(new ModelAndViewMethodReturnValueHandler());
    handlers.add(new ModelMethodProcessor());
    handlers.add(new ViewMethodReturnValueHandler());
    handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
    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));

    // Multi-purpose return value types
    handlers.add(new ViewNameMethodReturnValueHandler());
    handlers.add(new MapMethodProcessor());

    // 自定义的返回值处理器,就是在以前parse处理的那些
    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;
}

从上能够看出,咱们虽然咱们的自定义返回值处理器放进去了,可是必定会用到嘛?那不必定哦。能够看到对全部的返回值处理器,并无进行排序,所以咱们不能控制这个顺序。先给一个调试的图:

customReturnValueHandler

从图中咱们可看到,咱们自定义的handler确实是加载进去了,可是因为spring在处理这个handlers的时候并无进行排序,因此咱们自定义被放在了后面,咱们不可以控制这个顺序(其余骚方法能够实现,这里不考虑这种状况)。因此存在一种状况,咱们的返回值可以被前面的11个处理器中的某一个处理,那么就轮不到咱们自定义的返回值处理器了。举个简单的例子,好比你返回值类型是String,那么就会别ViewNameMethodReturnValueHandler处理;若是返回的类型是Map,那么就会被MapMethodProcessor处理,能够自行测试。所以咱们的返回值其实也很重要。因此要使用到咱们自定义的处理器,那么首先咱们就得让前面的处理器没法处理咱们的返回结果

一般能够实现一个通用的返回结果实体,或者某个标记接口(空接口),这样其余的返回值处理器没法处理返回的值类型,这样就轮到咱们本身的返回值处理器了。也能够返回喜欢的实体类型,像示例中同样使用注解也能够。可是由于一般一个项目来说返回值都是有定义的,返回的类型都是有同一种格式的,因此这类比较偏向使用通用相同的返回实体,或者使用某个接口标记。

over ...

相关文章
相关标签/搜索