【spring】- springmvc 工做原理

核心:前端控制器:DispatcherServlet前端

功能:MVC設計模式中的Controller角色,掌控全局web


類圖


原理

本質是將DispatcherServlet及關聯的Spring上下文環境的初始化工做織入Servlet的生命週期內,將外部WEB請求轉換爲Spring Bean能處理的形式,而後將處理後的結果藉助於符合J2EE規範組件,呈現給客戶端。spring

步驟

  1. HttpServletBean: init(),內部調用initServletBean完成Servlet的初始化設計模式

  2. FrameworkServlet 重寫 initServletBean()方法,方法內部調用 initWebApplicationContext()方法完成與DispatcherServlet關聯的web應用上下文的初始化工做,應用環境的基礎環境的初始化工做由子類DispatcherServlet的onRefresh方法完成。tomcat

  3. DispatcherServlet.onRefresh方法內部調用:initStrategies方法完成Springmvc須要的各類組件的初始化工做,至此springmvc可提供完整的外部應用訪問功能。mvc

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

springmvc 默認配置文件:DispatcherServlet.propertiesapp


Springmvc 客戶端請求處理過程

核心方法:doService,本質是對Serlvet接口的service方法的最終實現。async

doService:完成應用請求的數據封裝封裝,內部調用doDispatch方法完成請求調度調度處理源碼分析

源碼分析:post

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 {
		//判斷外部請求是不是多部分請求(通常用於文件上傳)
			processedRequest = checkMultipart(request);  
			multipartRequestParsed = processedRequest != request;

			// 根據請求請求獲取請求處理器:注意這裏會返回對應的處理器以及潛在的攔截器
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// 獲取可以支持請求處理器的處理器適配器
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (logger.isDebugEnabled()) {
					String requestUri = urlPathHelper.getRequestUri(request);
					logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
				}
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			//前置攔截器攔截請求
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			try {
				// 處理器適配器將請求傳遞給控制器處理,獲取ModelView對象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			}
			finally {
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
			}
								
			//設置視圖名
			applyDefaultViewName(request, mv);

			//後置攔截器攔截請求
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}

		//處理控制器返回的結果ModelAndView,主要是講model的數據填充view,渲染後將數據返回給客戶端顯示
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Error err) {
		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			return;
		}
		// Clean up any resources used by a multipart request.
		if (multipartRequestParsed) {
			cleanupMultipart(processedRequest);
		}
	}
}

springmvc 請求響應:

主要是將MappingHandler返回的ModelAndView種的Model數據填充到view,並藉助於servlet容器(例如tomcat)呈現給客戶端。

AbstractView. render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response):

//具體執行代碼
renderMergedOutputModel(mergedModel, request, response);

案例分析:內部資源視圖(例JSP) InternalResourceView. renderMergedOutputModel

protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		//封裝客戶端可視的請求資源數據
		HttpServletRequest requestToExpose = getRequestToExpose(request);
		exposeModelAsRequestAttributes(model, requestToExpose);

		//客戶端請求添加輔助信息
		exposeHelpers(requestToExpose);

		// 獲取請求轉發路徑
		String dispatcherPath = prepareForRendering(requestToExpose, response);

		//獲取目標資源的請求調度器
		RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		//若是一個URL的內部請求則進行響應資源追加,例如網頁內的圖片連接等
		if (useInclude(requestToExpose, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(requestToExpose, response);
		}
		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}

			//repuest請求轉發,說明springmvc採用的轉發而不是重定向的方式
			rd.forward(requestToExpose, response);
		}
	}
相關文章
相關標籤/搜索