springMVC工作原理简单分析

springMVC实现了模型与视图的分离,其中M是模型model,V是视图View,C是控制器Controller,核心类DispatcherServlet的继承关系如下:

 

 其本质就是一个Servlet,所以处理请求关注的是 doService 方法,在doService 方法中,可以看到调用了:

doDispatch(request, response);

看看 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 {
                // 检查是否是文件上传请求,通过content-type是否以"multipart/"开头判断
				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.
                // 获取处理器适配器,我们使用的一般是RequestMappingHandlerAdapter
				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;
					}
				}
                // 执行拦截器的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                // 执行目标方法,也就是真正的处理当前请求,返回ModelAndView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
                // 执行拦截器的postHandle方法
				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) {
            // 触发拦截器的afterCompletion方法
			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)请求来到DispatcherServlet

(2)根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链

(3)获取处理器适配器,用来执行目标方法

(4)执行拦截器链的preHandle方法

(5)执行处理请求的方法,并返回ModelAndView对象

(6)执行拦截器链的postHandle方法

(7)根据(5)返回的ModelAndView对象,渲染视图

(8)执行拦截器链的aterCompletion方法

 

下面将简单分析以下两个部分:

(1)根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链

(2)执行处理请求的方法

 

一、根据请求url,找到找到处理器执行链,包含了处理请求的方法和相应的拦截器链

 

                // 获取处理执行器链,包括了当前请求的方法和拦截器链
				mappedHandler = getHandler(processedRequest);

 看看getHandler都做了什么:

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
            // 遍历所有的handlerMapping,只要有一个返回不为null,就是找到了
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

 可以看到,这里遍历了所有的handlerMapping,只要有一个返回不为null,就是找到了,那么handlerMappings都有哪些呢?

 

       可以看到,待遍历的集合handlerMappings只有两个元素,一个是RequestMappingHandlerMapping,另一个是BeanNameUrlHandlerMapping,我们使用是RequestMappingHandlerMapping,跟进去,来到AbstractHandlerMethodMapping

的 lookupHandlerMethod 方法:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

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

 关注这一句:

List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
发现,它会从MappingRegistry中获取已经注册了处理方法,key为url,value就是处理请求的方法:

 这样一来,自然可以根据请求的url来获取请求的方法了。

 

那么,它又是怎样获取拦截器链的呢?回到AbstractHandlerMapping的getHandler方法,有这样一行代码:

HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

其中,handler是处理当前请求的方法,executionChain 是最终要返回的结果

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        // 如果handler是HandlerExecutionChain就直接强转,否则就new一个
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        // 将所有的拦截器添加到HandlerExecutionChain中
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

 

二、执行处理请求的方法

回到 DispatcherServlet 的 doDispatch 方法:

// Actually invoke the handler.
// 执行请求方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

跟进去,来到AbstractHandlerMethodAdapter

	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

handleInternal详细代码如下:

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

代码有点长,重点看这句:

			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);

这下来到了 RequestMappingHandlerAdapter 的 invokeHandlerMethod 方法:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        // 将request、response包装成ServletWebRequest 
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
            // 将请求方法handlerMethod包装成ServletInvocableHandlerMethod
			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();
				LogFormatUtils.traceDebug(logger, traceOn -> {
					String formatted = LogFormatUtils.formatValue(result, !traceOn);
					return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
            // 执行目标方法
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

重点看这句:

// 执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);

在执行目标方法的过程中,会进行参数绑定,然后通过反射执行目标方法

	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
         // 获取参数值
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
        // 执行目标方法
		return doInvoke(args);
	}

那么这里就是做了两件事:

(1)解析参数,获取参数值

(2)通过反射执行目标方法

难点在于如何解析参数,毕竟我们的处理请求的方法,参数是不确定的,而执行目标方法,就是通过反射,没多大的研究价值

 

那么接下来,看看如何解析参数:

InvocableHandlerMethod的getMethodArgumentValues方法详情:
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		if (ObjectUtils.isEmpty(getMethodParameters())) {
			return EMPTY_ARGS;
		}
        // 获取所有的参数
		MethodParameter[] parameters = getMethodParameters();
		Object[] args = new Object[parameters.length];
        // 遍历参数,锁定参数值
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
            // 如果没有参数解析器能够解析,就抛出异常
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
                // 通过参数解析器,解析参数
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled..
				if (logger.isDebugEnabled()) {
					String error = ex.getMessage();
					if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, error));
					}
				}
				throw ex;
			}
		}
		return args;
	}

这个方法的逻辑是,先获取所有的参数,然后遍历参数,逐个赋值

                // 通过参数解析器,解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request,this.dataBinderFactory);

值得注意的是,不同类型的参数,会使用不同的参数解析器,参数解析器多达26个,那么如果判断参数解析器是否支持指定参数的解析呢?请看HandlerMethodArgumentResolverComposite的getArgumentResolver方法:

	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
       // 从缓存中获取
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
            // 遍历所有的参数解析器,调用其supportsParameter来判断是否支持
			for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
				if (methodArgumentResolver.supportsParameter(parameter)) {
					result = methodArgumentResolver;
                    // 将支持该参数解析的参数解析器放入缓存中
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

这里的参数解析器很多,比如RequestParamMethodArgumentResolver,就是用来解析添加了@RequestParam参数的,而PathVariableMethodArgumentResolver则是用来解析添加了@PathVariable参数的,我们常用的解析pojo对象的是ServletModelAttributeMethodProcessor这个参数解析器。

对于简单类型的参数,最后都是通过request.getParameter方法来获取参数值的

而对于pojo对象,则是先创建对象,再通过反射设置属性值的

这里的实现都比较复杂,我也只是看了一个大概,就是简单记录一下

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值