springMVCはどのようにビューを解決するのですか?

SpringMVCはリクエストからの解析済みビューをどのように配布するのですか?

最初にSpringMVCの9つの主要コンポーネントを理解する

// 文件解析
/** MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver;
// 国际化解析
/** LocaleResolver used by this servlet. */
@Nullable
private LocaleResolver localeResolver;
// 主题解析器
/** ThemeResolver used by this servlet. */
@Nullable
private ThemeResolver themeResolver;
// 映射表
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
// 适配器表
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
// 异常处理
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
//请求转视图名
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
// 重定向数据
/** FlashMapManager used by this servlet. */
@Nullable
private FlashMapManager flashMapManager;
// 视图解析器
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;

1. htttpリクエストを受信する

2.フィルタリングリクエストには、一連のフィルタリングが含まれています。一般にdofilterメソッドです。

3. DispatchSerlet.classを使用してリクエストを処理する(コアクラス)

4. handleMappingsを使用して、リクエストに従って処理する必要があるコントローラーとターゲットメソッドを見つけます。

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

それを見つける方法は?

@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

すべてのHandlerMappingをトラバースするのは簡単です

HandlerMappingを初期化するプロセスで、少なくとも1つのhandlerMappingがあります

// handlerMappings的初始化
private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

5.ハンドラーに応じて適切なhandlerAdapterを選択します

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

6.ターゲットメソッドを実行し、ModelAndViewを生成します。

アダプター

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   

POJOをテストします。文字列型には実際には戻り値しかないため、現時点ではmav = null;

7. ModelAndViewに従って結果を返す

レンダービューを表示し、そうでない場合はビューのロードをスキップします

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

フローチャートは以下の通りです

ここに画像の説明を挿入

DispatcherServletコアメソッドdodispatch:

	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);
				// 找到处理这个请求的Controller
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
                		// 没有找到处理的Controller准备返回
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

                  		// 处理适配器
				// Determine handler adapter for the current request.
				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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 生成ModelAndView (最最最核心的部分)
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				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);
			}
            	// 渲染ModelAndView 到页面
			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);
				}
			}
		}
	}

その結果

明らかにSpringMVCはアダプターモード

異なる方法に従って異なるクラスを選択する

元の記事を22件公開 Likes2 Visits 881

おすすめ

転載: blog.csdn.net/weixin_41685373/article/details/104973688