中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

spring webmvc請求處理流程中返回值處理是什么

發布時間:2021-10-19 17:30:02 來源:億速云 閱讀:112 作者:柒染 欄目:大數據

這期內容當中小編將會給大家帶來有關spring webmvc請求處理流程中返回值處理是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

spring-webmvc請求處理流程——返回值處理

講解3.2.x版本之后使用的RequestMappingHandlerAdapter,該類替換了AnnotationMethodHandlerAdapter。

RequestMappingHandlerAdapter

自3.2之后的版本,引入了RequestMappingHandlerAdapter來替換了AnnotationMethodHandlerAdapter的處理。這里也來分析一下這個玩意兒。

因為也是一個HandlerAdapter,所以,前面的處理流程都是一樣的,servlet的getHandlerAdapter這個時候就返回了RequestMappingHandlerAdapter,而不是AnnotationMethodHandlerAdapter了。

拿到HandlerAdapter之后,我們就直接沖ha.handle()方法開始分析吧。

// 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方法。

調用業務方法,并處理返回值

//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類型的對象,繼續跟進。

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()方法就明白了。

spring webmvc請求處理流程中返回值處理是什么

到這里就不繼續跟了,我們熟悉的RequestResponseBodyMethodProcessor處理器處理結果的時候會設置mavContainer.setRequestHandled(true);表示處理已經完畢。

getModelAndView()

處理完之后,回到RequestMappingHandlerAdapter的invokeHandleMethod()方法。這個方法最終返回了getModelAndView();

從該方法中,我們可以看到,如果當前請求已經處理完成(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;
}

從上可以看出,我們雖然我們的自定義返回值處理器放進去了,但是一定會用到嘛?那不一定哦。可以看到對所有的返回值處理器,并沒有進行排序,因此我們不能控制這個順序。先給一個調試的圖:

spring webmvc請求處理流程中返回值處理是什么

從圖中我們可看到,我們自定義的handler確實是加載進去了,但是由于spring在處理這個handlers的時候并沒有進行排序,所以我們自定義被放在了后面,我們不能夠控制這個順序(其他騷方法可以實現,這里不考慮這種情況)。所以存在一種情況,我們的返回值能夠被前面的11個處理器中的某一個處理,那么就輪不到我們自定義的返回值處理器了。舉個簡單的例子,比如你返回值類型是String,那么就會別ViewNameMethodReturnValueHandler處理;如果返回的類型是Map,那么就會被MapMethodProcessor處理,可以自行測試。因此我們的返回值其實也很重要。所以要使用到我們自定義的處理器,那么首先我們就得讓前面的處理器無法處理我們的返回結果

通常可以實現一個通用的返回結果實體,或者某個標記接口(空接口),這樣其他的返回值處理器無法處理返回的值類型,這樣就輪到我們自己的返回值處理器了。也可以返回喜歡的實體類型,像示例中一樣使用注解也可以。但是因為通常一個項目來講返回值都是有定義的,返回的類型都是有同一種格式的,所以這類比較偏向使用通用相同的返回實體,或者使用某個接口標記。

over ...

上述就是小編為大家分享的spring webmvc請求處理流程中返回值處理是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

清新县| 莎车县| 屯昌县| 石首市| 万盛区| 大足县| 阆中市| 永安市| 吕梁市| 芦山县| 调兵山市| 双柏县| 偃师市| 塔城市| 南靖县| 萨嘎县| 原平市| 江西省| 平度市| 岳阳市| 镇康县| 加查县| 名山县| 美姑县| 竹溪县| 韶山市| 姜堰市| 青冈县| 襄垣县| 丁青县| 盐津县| 郓城县| 四平市| 互助| 巴中市| 水富县| 进贤县| 报价| 中山市| 闻喜县| 远安县|