SpringBoot——MVC

一、Spring MVC

SpringMVC 核心为: DispatcherServlet >> 前端控制器

请求进入程序中,会进入DispatcherServlet类 , doService >> 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);

				// 通过遍历List<HandlerMapping> handlerMappings,寻找当前请求对应的处理程序
                //返回的是 当前请求对应的处理器和拦截器链对应的封装对象
                /**
                 * 遍历(List)handlerMappings,handlerMapping调用getHandler(request) -> getHandlerInternal(request) -> lookupHandlerMethod(lookupPath, request)
                 * 查询handlerMapping下是否存在与当前请求匹配的映射方法处理器,查找到之后,将处理器方法封装进HandlerExecutionChain处理器执行链对象返回
                 * @RequestMapping标注 路径注册进map MappingRegistry,从注册映射对象查询出最符合的处理器方法(handlerMethod)对象;
                 */
				mappedHandler = getHandler(processedRequest);
                //如果查询不到该请求对应的handler,当前请求流程终止,直接返回对应的处理;
				if (mappedHandler == null) {
                    //对于当前请求进行日志输出,并对本次请求做出处理,
					noHandlerFound(processedRequest, response);
					return;
				}

				// 查找(遍历)当前支持当前处理器handler的适配器,
                //这里是RequestMappingHandlerAdapter,调用@RequestMapping标注的方法
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
                //获取本次请求类型
				String method = request.getMethod();
                //判断是否为GET类型的请求
				boolean isGet = "GET".equals(method);
                //Spring MVC缓存机制
				if (isGet || "HEAD".equals(method)) {
                    //查询是否存在于缓存中,如果在的话,直接返回;
                    //这里类似于http请求与之前的没有改变时,则直接返回上次结果
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                //拦截器
                //顺序执行拦截器的preHandle方法(前置方法),如果任何一个拦截器返回false,执行返回,不执行目标方法。
				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);
			}
             // 根据ModelAndView对象解析视图
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
            //出现异常的话,倒序执行afterCompletion方法。
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
            //出现异常的话,倒序执行afterCompletion方法。
			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);
				}
			}
		}
	}

查找handlerMapping的过程


	@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;
	}

    @Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
		/*如果当前handlerMapping中未找到,获取默认的处理器*/
		if (handler == null) {
			handler = getDefaultHandler();
		}
		/*如果仍然为空,那么返回null*/
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		// 如果返回的是bean的名字,那么根据名字从容器中获取对应的处理器对象
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
        //组装处理器执行链对象
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

		if (logger.isTraceEnabled()) {
			logger.trace("Mapped to " + handler);
		}
		else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
			logger.debug("Mapped to " + executionChain.getHandler());
		}
        
		if (hasCorsConfigurationSource(handler)) {
			CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			config = (config != null ? config.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		/*返回处理器执行链对象*/
		return executionChain;
	}


	// Handler method lookup

	/**
	 * Look up a handler method for the given request.
	 */
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		/*获取当前请求的URI*/
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		/*将URI存放到请求中*/
		request.setAttribute(LOOKUP_PATH, lookupPath);
		/*开启同步锁*/
		this.mappingRegistry.acquireReadLock();
		try {
			/*根据URL查找最佳的请求映射方法处理器*/
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		/*关闭锁*/
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

    /**
     * 
     * 
	 * Look up the best-matching handler method for the current request.
	 * If multiple matches are found, the best match is selected.
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 * @return the best-matching handler method, or {@code null} if no match
	 * @see #handleMatch(Object, String, HttpServletRequest)
	 * @see #handleNoMatch(Set, String, HttpServletRequest)
	 */
	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		// 根据lookupPath获取对应的RequestMappingInfo列表
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			//对匹配到的列表做一次筛选
			// 根据上面获取到的RequestMappingInfo遍历来匹配HandlerMethod。
			//这个匹配涉及到多个条件:如请求方法、路径、参数等一系列信息,
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}
		/*最后筛选,选出一个最适合的handlerMethod*/
		if (!matches.isEmpty()) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				if (logger.isTraceEnabled()) {
					logger.trace(matches.size() + " matching mappings: " + matches);
				}
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					String uri = request.getRequestURI();
					throw new IllegalStateException(
							"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
				}
			}
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
			handleMatch(bestMatch.mapping, lookupPath, request);
			return bestMatch.handlerMethod;
		}
		else {
			/* 未匹配上 */
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//获取程序中注册的拦截器列表	
    //正序
    HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					// 反向遍历拦截器
                    triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
            //倒序执行拦截器的后置处理方法
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
                //倒序执行
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

一次请求执行过程如下

请求进入doService方法,再调用dispatch方法,

  1. 首先检查request中是否含有文件流
  2. 获取handler
    1. 遍历handlerMapping(7种)的方式获取到支持此请求的HandlerMethod
    2. 将HandlerMethod和容器中注册的拦截器封装成一个HandlerExecutionChain执行链
    3. 返回dispatch方法中
  1. 获取能够处理此请求对应的handler的handlerAdapted适配器
  2. 判断是否为GET或HEAD类型的请求...(MVC实现的请求缓存)
  3. 顺序执行拦截器链中的前置请求
  4. 使用处理器适配器执行处理器
    1. 参数的处理 --> 将参数解析器绑定在HandlerMethod对象上(invokeHandlerMethod方法)>> HandlerMethodArgumentResolver
    2. 根据参数解析器设置方法参数值
    3. 通过反射,调用处理器方法
  1. 逆序执行拦截器链的后置方法
  2. 视图处理
  3. 如果出现以上步骤异常,将会逆序执行拦截器链中的异常处理方法

请求映射扫描注册过程

请求返回值处理

参数解析器和类型转换器

  1. 参数解析器在获取的适配器对象属性上绑定,提供 supportsParameter 方法判断当前解析器是否可以处理参数和resolveArgument的处理实现
  2. 自定义类型转换器 Converter ,实现接口,注册web容器 --- 只对Key/Value形式的参数有效
  3. 请求体body中,是通过HttpMessageConverter (消息转换器)转换成其他对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值