欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring MVC請(qǐng)求參數(shù)的深入解析

 更新時(shí)間:2021年05月06日 11:48:39   作者:是馮吉榮呀  
這篇文章主要給大家介紹了關(guān)于Spring MVC請(qǐng)求參數(shù)解析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

請(qǐng)求參數(shù)解析

客戶端請(qǐng)求在handlerMapping中找到對(duì)應(yīng)handler后,將會(huì)繼續(xù)執(zhí)行DispatchServlet的doPatch()方法。

首先是找到handler對(duì)應(yīng)的適配器。

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

進(jìn)入到getHandlerAdapter(mappedHandler.getHandler())方法中

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

這里存在多個(gè)適配器,如圖:

其中使用@RequestMaping注解修飾的控制器都將適配第一個(gè)適配器;而函數(shù)式方法將會(huì)使用第二個(gè)適配器。

跟蹤請(qǐng)求,這里將會(huì)獲得第一個(gè)適配器,判斷也簡(jiǎn)單,如下:

public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

如果是HandlerMethod類型的處理器就采用這個(gè)適配器,而客戶端請(qǐng)求正好對(duì)應(yīng)的是HandlerMethod處理器。

找到適配器后,將會(huì)真正執(zhí)行處理器邏輯。如下:

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

進(jìn)入RequestMappingHandlerAdapter,執(zhí)行適配器核心方法:

@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}

其核心代碼為實(shí)際執(zhí)行處理器方法:

mav = invokeHandlerMethod(request, response, handlerMethod);

同樣,我們打開RequestMappingHandlerAdapter中的invokeHandlerMethod方法:

@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
            //通過處理器獲得真正的執(zhí)行方法及其參數(shù)列表
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            //給執(zhí)行方法對(duì)象添加參數(shù)解析器
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
            //給執(zhí)行方法對(duì)象添加返回值處理器
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
            //處理器對(duì)象裝配完成,執(zhí)行控制器方法
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

在這個(gè)關(guān)鍵方法中,首先執(zhí)行請(qǐng)求對(duì)應(yīng)的控制器邏輯,之后進(jìn)行系列處理,根據(jù)返回值處理器處理返回值。

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //執(zhí)行控制器方法
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		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) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throw ex;
		}
	}

以下給出部分參數(shù)解析器及返回值處理器截圖:

參數(shù)解析器。對(duì)應(yīng)每一個(gè)參數(shù)(路徑變量、矩陣變量、獲得請(qǐng)求頭、請(qǐng)求域等)的獲取方式

返回值處理器。ModelAndView、ResponseBody等。每個(gè)處理器處理不同類別的返回值類型。

接下來,真正進(jìn)入到最終執(zhí)行method方法invocableMethod.invokeAndHandle(webRequest, mavContainer);,這里是真是執(zhí)行控制器中映射的方法。

以下為獲得參數(shù)列表對(duì)應(yīng)值的邏輯,參數(shù)獲取完成后將會(huì)執(zhí)行真正的控制器邏輯。

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
    //通過參數(shù)解析器獲取參數(shù)列表每一個(gè)參數(shù)的值
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		return doInvoke(args);
	}

進(jìn)入解析邏輯,解析是對(duì)比每一個(gè)參數(shù)綁定的注解,如果注解一致將會(huì)使用對(duì)應(yīng)的解析器將請(qǐng)求傳遞的參數(shù)值獲取到。

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //獲得控制器參數(shù)列表,每一個(gè)參數(shù)包含其參數(shù)類型,參數(shù)次序、注解修飾(用于使用對(duì)應(yīng)解析器)
		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}

		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
            //輪循獲得參數(shù)
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
            //判斷解析器是否支持當(dāng)前參數(shù)的解析
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
                //獲得參數(shù)值的核心方法
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}

查看解析器是否指出當(dāng)前參數(shù)部分代碼,可以了解到SpringMVC的緩存策略。

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    //從緩存中獲取當(dāng)前參數(shù)的解析器
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
	//緩存中不存在則將這個(gè)參數(shù)對(duì)應(yīng)的解析器加到緩存中,提升后續(xù)相同請(qǐng)求響應(yīng)速度。	
    if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

參數(shù)列表

以下為獲得的參數(shù)列表第一個(gè)參數(shù)部分屬性

其對(duì)應(yīng)的是控制器中id參數(shù):

@GetMapping(value = "/student01/{id}/car/{name}")
    public Map<String, Object> testAnnotation(@PathVariable(name = "id") String id){
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
    return map;
    }

以上即為獲得請(qǐng)求Handler對(duì)應(yīng)的適配器,處理參數(shù)映射、執(zhí)行控制器邏輯、返回值處理的核心源碼處理。

總結(jié)

到此這篇關(guān)于Spring MVC請(qǐng)求參數(shù)解析的文章就介紹到這了,更多相關(guān)SpringMVC請(qǐng)求參數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring聲明式事務(wù)解析

    spring聲明式事務(wù)解析

    這篇文章主要為大家詳細(xì)介紹了spring聲明式事務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 解決SpringMVC同時(shí)接收J(rèn)son和Restful時(shí)Request里有Map的問題

    解決SpringMVC同時(shí)接收J(rèn)son和Restful時(shí)Request里有Map的問題

    今天小編就為大家分享一篇解決SpringMVC同時(shí)接收J(rèn)son和Restful時(shí)Request里有Map的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • java實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出

    java實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出

    這篇文章主要介紹了java實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出的方法和具體示例代碼,非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下
    2016-04-04
  • Java 8中如何獲取參數(shù)名稱的方法示例

    Java 8中如何獲取參數(shù)名稱的方法示例

    這篇文章主要給大家介紹了在Java 8中如何獲取參數(shù)名稱的方法,文中給出了詳細(xì)的介紹和方法示例,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,有需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。
    2017-01-01
  • SpringMVC實(shí)現(xiàn)注解式權(quán)限驗(yàn)證的實(shí)例

    SpringMVC實(shí)現(xiàn)注解式權(quán)限驗(yàn)證的實(shí)例

    本篇文章主要介紹了SpringMVC實(shí)現(xiàn)注解式權(quán)限驗(yàn)證的實(shí)例,可以使用Spring MVC中的action攔截器來實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解下。
    2017-02-02
  • Spring基于XML實(shí)現(xiàn)Aop

    Spring基于XML實(shí)現(xiàn)Aop

    這篇文章主要介紹了Spring中基于xml的AOP的詳細(xì)步驟,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • Jenkins初級(jí)應(yīng)用之Invoke?Phing?targets插件配置

    Jenkins初級(jí)應(yīng)用之Invoke?Phing?targets插件配置

    這篇文章主要為大家介紹了Jenkins初級(jí)應(yīng)用之Invoke?Phing?targets的插件配置,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪<BR>
    2022-04-04
  • SpringBoot解析JSON數(shù)據(jù)的三種方案

    SpringBoot解析JSON數(shù)據(jù)的三種方案

    JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式,易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,本文給大家介紹了SpringBoot解析JSON數(shù)據(jù)的三種方案,需要的朋友可以參考下
    2024-03-03
  • SpringMVC整合kinfe4j及問題解決分析

    SpringMVC整合kinfe4j及問題解決分析

    這篇文章主要為大家介紹了SpringMVC整合kinfe4j及問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Java中List遍歷刪除元素remove()的方法

    Java中List遍歷刪除元素remove()的方法

    這篇文章主要介紹了Java中List遍歷刪除元素remove()的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評(píng)論