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

Java?spring?mvc請求詳情介紹

 更新時間:2022年03月29日 15:06:45   作者:zfcq  
這篇文章主要介紹了Java?spring?mvc請求詳情,mvc是spring源碼中的一個子模塊,下文關(guān)于spring?mvc請求的相關(guān)資料做簡單介紹,需要的小伙伴可以參考一下,希望對你有所幫助

前言:

  • 本文源碼基于spring-framework-5.3.10。
  • mvcspring源碼中的一個子模塊!

一、源碼執(zhí)行流程

  • 用戶發(fā)送請求至前端控制器DispatcherServlet。
  • DispatcherServlet收到請求調(diào)用處理器映射器HandlerMapping。處理器映射器根據(jù)請求url找到具體的處理器,生成處理器執(zhí)行鏈HandlerExecutionChain(包括處理器對象和處理器攔截器)一并返回給DispatcherServlet。
  • DispatcherServlet根據(jù)處理器Handler獲取處理器適配器HandlerAdapter,執(zhí)行HandlerAdapter處理一系列的操作,如:參數(shù)封裝,數(shù)據(jù)格式轉(zhuǎn)換,數(shù)據(jù)驗證等操作
  • 執(zhí)行處理器Handler(Controller,也叫頁面控制器)。Handler執(zhí)行完成返回ModelAndView、HandlerAdapter將Handler執(zhí)行結(jié)果ModelAndView返回到DispatcherServlet。
  • DispatcherServletModelAndView傳給ViewReslover視圖解析器。ViewReslover解析后返回具體View
  • DispatcherServlet對View進行渲染視圖(即將模型數(shù)據(jù)model填充至視圖中)。
  • DispatcherServlet響應(yīng)用戶。

二、源碼執(zhí)行流程圖

三、spring mvc中的一核心組件

  • DispatcherServlet: 前端調(diào)度器 , 負責(zé)將請求攔截下來分發(fā)到各控制器方法中
  • HandlerMapping: 負責(zé)根據(jù)請求的URL和配置@RequestMapping映射去匹配, 匹配到會返回Handler(具體控制器的方法)
  • HandlerAdaper: 負責(zé)調(diào)用Handler-具體的方法- 返回視圖的名字 Handler將它封裝到ModelAndView(封裝視圖名,request域的數(shù)據(jù))
  • ViewReslover: 根據(jù)ModelAndView里面的視圖名地址去找到具體的jsp封裝在View對象中
  • View:進行視圖渲染(將jsp轉(zhuǎn)換成html內(nèi)容 --這是Servlet容器的事情了) 最終response到的客戶端

四、源碼分析

/**
 * 最核心的控制器
 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			// 驗證是不是上傳的請求,上傳的請求會轉(zhuǎn)化為MultipartHttpServletRequest
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// 進行映射
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// 找到最合適的HandlerAdapter,按照順序,那個先解析到就是那個
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.  HTTP緩存相關(guān)
			String method = request.getMethod();
			boolean isGet = HttpMethod.GET.matches(method);
			if (isGet || HttpMethod.HEAD.matches(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
			// 前置攔截器
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				// 返回false就不進行后續(xù)處理了
				return;
			}

			// Actually invoke the handler.
			// 獲取參數(shù),執(zhí)行方法
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			// 如果mv有  視圖沒有,給你設(shè)置默認視圖
			applyDefaultViewName(processedRequest, mv);
			//后置攔截器
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		catch (Throwable err) {
			// As of 4.3, we're processing Errors thrown from handler methods as well,
			// making them available for @ExceptionHandler methods and other scenarios.
			dispatchException = new NestedServletException("Handler dispatch failed", err);
		}
		// 渲染視圖
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Throwable err) {
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				new NestedServletException("Handler processing failed", err));
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		}
		else {
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
}

五、獲取組件相關(guān)邏輯:

原理:誰先解析到就用誰!

/**
 * 獲取處理器映射器
 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest)
 */
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		/** 拿到所有handlerMappings (容器啟動階段初始化:拿到所有實現(xiàn)了HandlerMapping的Bean)
		 * @see DispatcherServlet#initHandlerMappings
		 * 測試發(fā)現(xiàn): 不同的HandlerMapping可以有相同path, 誰先解析到就用哪個
		 * */
		for (HandlerMapping mapping : this.handlerMappings) {
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

/**
 * 獲取處理器適配器
 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(Object)
 */
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");
}

六、獲取參數(shù),執(zhí)行方法源碼分析

/**
 * 獲取參數(shù),執(zhí)行方法最外層的調(diào)用
 * 源碼位置:org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(HttpServletRequest, HttpServletResponse, Object)
 */
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	// 直接調(diào)用這個方法
	return handleInternal(request, response, (HandlerMethod) handler);
}

/**
 * 獲取參數(shù),執(zhí)行方法內(nèi)部的調(diào)用邏輯
 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod)
 */
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	// 檢查當前請求的method是否為支持的method(默認Null,可通過繼承AbstractController設(shè)置supportedMethods)
	// 檢查當前請求是否必須session  (默認false,可通過繼承AbstractController設(shè)置requireSession)
	checkRequest(request);

	/**
	 * 判斷當前是否需要支持在同一個session中只能線性地處理請求:一個session同時只能處理一個線程
	 * 因為鎖是通過 synchronized 是 JVM 進程級,所以在分布式環(huán)境下,
	 * 無法達到同步相同 Session 的功能。默認情況下,synchronizeOnSession 為 false
	 */
	if (this.synchronizeOnSession) {
		// 獲取當前請求的session對象
		HttpSession session = request.getSession(false);
		if (session != null) {
			// 為當前session生成一個唯一的可以用于鎖定的key
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				// 對HandlerMethod進行參數(shù)等的適配處理,并調(diào)用目標handler
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// 如果當前不存在session,則直接對HandlerMethod進行適配
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// *如果當前不需要對session進行同步處理,則直接對HandlerMethod進行適配
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}


	//判斷當前請求頭中是否包含Cache-Control請求頭,如果不包含,則對當前response進行處理
	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		// 如果當前SessionAttribute中存在配置的attributes,則為其設(shè)置過期時間。
		// 這里SessionAttribute主要是通過@SessionAttribute注解生成的
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			// 如果當前不存在SessionAttributes,則判斷當前是否存在Cache-Control設(shè)置,
			// 如果存在,則按照該設(shè)置進行response處理,如果不存在,則設(shè)置response中的
			// Cache的過期時間為-1,即立即失效
			prepareResponse(response);
		}
	}

	return mav;
}

/**
 * 獲取參數(shù),執(zhí)行方法前的準備邏輯
 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod)
 */
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	// 把我們的請求req resp包裝成 ServletWebRequest
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		// 獲取容器中全局配置的InitBinder和當前HandlerMethod所對應(yīng)的Controller中
		// 配置的InitBinder,用于進行參數(shù)的綁定
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

		// 獲取容器中全局配置的ModelAttribute和當前HandlerMethod所對應(yīng)的Controller 中配置的ModelAttribute,
		// 這些配置的方法將會在目標方法調(diào)用之前進行調(diào)用
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		// 封裝handlerMethod,會在調(diào)用前解析參數(shù)、調(diào)用后對返回值進行處理
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		if (this.argumentResolvers != null) {
			// 讓invocableMethod擁有參數(shù)解析能力
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		if (this.returnValueHandlers != null) {
			// 讓invocableMethod擁有返回值處理能力
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		// 讓invocableMethod擁有InitBinder解析能力
		invocableMethod.setDataBinderFactory(binderFactory);
		// 設(shè)置ParameterNameDiscoverer,該對象將按照一定的規(guī)則獲取當前參數(shù)的名稱
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		// ModelAndView處理容器
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		// 將request的Attribute復(fù)制一份到ModelMap
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// *調(diào)用我們標注了@ModelAttribute的方法,主要是為我們的目標方法預(yù)加載
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		// 重定向的時候,忽略model中的數(shù)據(jù) 默認false
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		// 獲取當前的AsyncWebRequest,這里AsyncWebRequest的主要作用是用于判斷目標
		// handler的返回值是否為WebAsyncTask或DeferredResult,如果是這兩種中的一種,
		// 則說明當前請求的處理應(yīng)該是異步的。所謂的異步,指的是當前請求會將Controller中
		// 封裝的業(yè)務(wù)邏輯放到一個線程池中進行調(diào)用,待該調(diào)用有返回結(jié)果之后再返回到response中。
		// 這種處理的優(yōu)點在于用于請求分發(fā)的線程能夠解放出來,從而處理更多的請求,提高吞吐。
		// 只有待目標任務(wù)完成之后才會回來將該異步任務(wù)的結(jié)果返回。
		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);
		// 封裝異步任務(wù)的線程池、request、interceptors到WebAsyncManager中
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		// 這里就是用于判斷當前請求是否有異步任務(wù)結(jié)果的,如果存在,則對異步任務(wù)結(jié)果進行封裝
		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);
		}
		// *對請求參數(shù)進行處理,調(diào)用目標HandlerMethod,并且將返回值封裝為一個ModelAndView對象
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		// 對封裝的ModelAndView進行處理,主要是判斷當前請求是否進行了重定向,如果進行了重定向,
		// 還會判斷是否需要將FlashAttributes封裝到新的請求中
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

/**
 * 獲取參數(shù),執(zhí)行方法
 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...)
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	/*真正的調(diào)用我們的目標對象 很重要 很重要*/
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	// 設(shè)置相關(guān)的返回狀態(tài)
	setResponseStatus(webRequest);
	// 如果請求處理完成,則設(shè)置requestHandled屬性
	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			disableContentCachingIfNecessary(webRequest);
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	// 如果請求失敗,但是有錯誤原因,那么也會設(shè)置requestHandled屬性
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
		// 遍歷當前容器中所有ReturnValueHandler,判斷哪種handler支持當前返回值的處理,
		// 如果支持,則使用該handler處理該返回值
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

七、渲染視圖邏輯

/**
 * 渲染視圖邏輯
 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.processDispatchResult(HttpServletRequest, HttpServletResponse, HandlerExecutionChain, ModelAndView, Exception)
 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {

	boolean errorView = false;

	// 異常視圖
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}

	// Did the handler return a view to render?
	if (mv != null && !mv.wasCleared()) {
		// 解析、渲染視圖:解析視圖名,拼接前后綴
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("No view rendering, null ModelAndView returned.");
		}
	}

	if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
		// Concurrent handling started during a forward
		return;
	}

	if (mappedHandler != null) {
		// Exception (if any) is already handled..   攔截器:AfterCompletion
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

到此這篇關(guān)于Java spring mvc請求詳情介紹的文章就介紹到這了,更多相關(guān)spring mvc請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot全局配置long轉(zhuǎn)String丟失精度問題解決方案

    SpringBoot全局配置long轉(zhuǎn)String丟失精度問題解決方案

    這篇文章主要介紹了SpringBoot全局配置long轉(zhuǎn)String丟失精度問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • Java基礎(chǔ)篇_有關(guān)接口和抽象類的幾道練習(xí)題(分享)

    Java基礎(chǔ)篇_有關(guān)接口和抽象類的幾道練習(xí)題(分享)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)篇_有關(guān)接口和抽象類的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例

    微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例

    這篇文章主要介紹了微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Spring Boot命令行啟動添加參數(shù)的三種方式

    Spring Boot命令行啟動添加參數(shù)的三種方式

    在命令行中,常見的參數(shù)可以分為三類:選項參數(shù)、非選項參數(shù)和系統(tǒng)參數(shù),本文就來介紹一下Spring Boot命令行三種參數(shù)形式,感興趣的可以了解一下
    2023-09-09
  • 逆波蘭計算器(Java實現(xiàn))

    逆波蘭計算器(Java實現(xiàn))

    這篇文章主要為大家詳細介紹了Java實現(xiàn)逆波蘭計算器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Java調(diào)用CMD命令的方法與使用技巧

    Java調(diào)用CMD命令的方法與使用技巧

    在實際的開發(fā)中我們有可能會遇到?java調(diào)用?cmd命令的情況,這篇文章主要給大家介紹了關(guān)于Java調(diào)用CMD命令的方法與使用的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-09-09
  • Java中死鎖產(chǎn)生的原因有哪些?

    Java中死鎖產(chǎn)生的原因有哪些?

    這篇文章主要介紹了Java中死鎖產(chǎn)生的原因有哪些?死鎖即Dead?Lock指的是兩個或兩個以上的運算單元,下文關(guān)于其產(chǎn)生的原因,需要的小伙伴可以參考一下
    2022-05-05
  • JDK1.8新特性之方法引用 ::和Optional詳解

    JDK1.8新特性之方法引用 ::和Optional詳解

    這篇文章主要介紹了JDK1.8新特性之方法引用 ::和Optional,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Mybatis-Plus中and()和or()的使用與原理詳解

    Mybatis-Plus中and()和or()的使用與原理詳解

    最近發(fā)現(xiàn)MyBatisPlus還是挺好用的,下面這篇文章主要給大家介紹了關(guān)于Mybatis-Plus中and()和or()的使用與原理的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • java不同版本在多線程中使用隨機數(shù)生成器的實現(xiàn)

    java不同版本在多線程中使用隨機數(shù)生成器的實現(xiàn)

    本文主要介紹了java不同版本在多線程中使用隨機數(shù)生成器的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評論