SpringMVC的执行流程和组件解析

1. SpringMVC的执行流程

在这里插入图片描述
在这里插入图片描述

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);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				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 (logger.isDebugEnabled()) {
    
    
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    
    
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    
    
					return;
				}

				// 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);
			}
			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);
				}
			}
		}
	}

1.1 客户端发送请求致DispatcherServlet

1.1.1 调用doDispatch(request, response);方法

  1. 检查请求是否是文件上传请求:
    processedRequest = checkMultipart(request);
  2. 根据请求地址找到哪个类能来处理该请求
    mappedHandler = getHandler(processedRequest);
    • 遍历所有handlerMappings看哪个handlerMapping的handlerMap属性中有这个请求映射信息,找到就返回该执行链HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    
    
		if (this.handlerMappings != null) {
    
    
			for (HandlerMapping hm : this.handlerMappings) {
    
    
				if (logger.isTraceEnabled()) {
    
    
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
    
    
					return handler;
				}
			}
		}
		return null;
	}
  1. 根据这个处理器拿到执行这个类方法的适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    • 遍历所有handlerAdapters看哪个HandlerAdapter(RequestMappingHandlerAdapter)能支持传递过来的Handler就返回该HandlerAdapter
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    
    
		if (this.handlerAdapters != null) {
    
    
			for (HandlerAdapter ha : this.handlerAdapters) {
    
    
				if (logger.isTraceEnabled()) {
    
    
					logger.trace("Testing handler adapter [" + ha + "]");
				}
				if (ha.supports(handler)) {
    
    
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}
  1. 利用得到的适配器执行目标方法,并返回ModelAndView(源码太多了自己看看.)
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    • 将处理器Handler转化成处理器方法HandlerMethod调用handleInternal方法
    • 执行处理器方法返回ModelAndView
      ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod);
    • invokeHandlerMethod中执行invocableMethod.invokeAndHandle(webRequest, mavContainer);方法set一些值
    • Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);反射获得方法参数
    • Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
    
    

		return handleInternal(request, response, (HandlerMethod) handler);
	}
@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;
	}
@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
    
    
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
    
    
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
    
    
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
    
    
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
    
    
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
    
    
			webRequest.requestCompleted();
		}
	}
  1. 根据方法最终执行完成后封装的ModelAndView转发或重定向到对应页面
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    • 调用**render(mv, request, response);**渲染页面
    • 根据视图名获得view对象
      view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
      • 遍历所有视图解析器viewResolvers如果能通过视图名返回view对象则返回
    • 得到view对象调用
      view.render(mv.getModelInternal(), request, response);
      • 调用**renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);**方法渲染要对页面输出的所有数据
        • 调用**exposeModelAsRequestAttributes(model, request);**方法将模型中所有数据暴露在request域中
        • 调用**String dispatcherPath = prepareForRendering(request, response);**拿到转发路径
        • 调用**RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);**获取转发器
        • 最后请求转发rd.include(request, response);

总结:视图解析器是为了得到视图对象,视图对象才能真正的转发(将模型数据防砸器请求域中)或者重定向到页面

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
		// Determine locale for request and apply it to the response.
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		View view;
		String viewName = mv.getViewName();
		if (viewName != null) {
    
    
			// We need to resolve the view name.
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			if (view == null) {
    
    
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
    
    
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
    
    
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
    
    
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
    
    
			if (mv.getStatus() != null) {
    
    
				response.setStatus(mv.getStatus().value());
			}
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
    
    
			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}
	@Nullable
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
    
    

		if (this.viewResolvers != null) {
    
    
			for (ViewResolver viewResolver : this.viewResolvers) {
    
    
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
    
    
					return view;
				}
			}
		}
		return null;
	}
	@Override
	public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
    
    

		if (logger.isTraceEnabled()) {
    
    
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}
	@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
    
    
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
    
    
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(request, 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() + "'");
			}
			rd.forward(request, response);
		}
	}

2. SpringMVC的九大组件

2.1组件

	@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. 文件上传解析器:MultipartResolver
  2. 区域信息解析器(国际化):LocaleResolver
  3. 主题解析器:ThemeResolver
  4. 处理器映射器:HandlerMapping
  5. 处理器适配器:HandlerAdapter
  6. 处理器异常解析器:HandlerExceptionResolver
  7. 视图名转换器:RequestToViewNameTranslator
  8. 地图管理器(SpringMVC重定向携带数据):FlashMapManager
  9. 视图解析器:ViewResolver

2.2 组件初始化

  1. IOC容器创建调用onRefresh()方法DispatcherServlet重写该方法初始化组件
  2. 以initHandlerMappings(context);为例,去容器中找该组件(有的通过类型找,有的通过ID找),如果找到就用,没有找到就用默认的配置(DispatcherServlet.properties)。
  3. 之后比如获得Handler过程中遍历所有的handlerMappings就是这个时候初始化的。
	@Override
	protected void onRefresh(ApplicationContext context) {
    
    
		initStrategies(context);
	}
	protected void initStrategies(ApplicationContext context) {
    
    
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
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.isDebugEnabled()) {
    
    
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

有错误欢迎大佬指出
以上只是粗略流程还是要自己看源码鸭!

猜你喜欢

转载自blog.csdn.net/weixin_48922154/article/details/113867510