02-DispatcherServlet调度

DispatcherServlet调度

  • 前文分析了DispatcherServlet的初始化,本文重点看DispatcherServlet处理请求的细节。

一、处理流程图

在这里插入图片描述

  • 1.首先是DispatcherServlet完成initStrategies初始化相关策略
  • 2.收到响应之后,遍历内部的HandMapping策略集合,找到对应的HandleMapping,HandMapping会遍历所有的控制器方法,保存映射关系,这部分可参考:HandlerMapping
  • 3.通过HandMapping拿到HandlerExecutionChain之后,将其封装成HandlerAdapter,Adapter内部封装了HandlerMethod用于执行目标方法
  • 4.Adapter开始执行,依次执行拦截器前置方法,然后执行目标方法得到ModeAndView,再将ModeAndView通过视图解析器处理得到结果示图,然后执行后置方法,这里需要注意的是HandlerMethod封装了目标方法所属的Bean对象,通过反射调用目标方法(Method.invoke(Object,arg));
  • 5.与此同时Adapter还会处理很多参数相关的细节,实现参数绑定,异常处理等;
  • 6.最后渲染View得到包含数据的View,再回调成功后回调方法afterCompletion,返回结果
注意DispatcherServlet本身的处理方法比如doDispatch没有返回值,但是处理完之后会进入父类的逻辑,比如FrameworkServlet,后续会返回响应。

二、处理方法

  • 下图是访问一个Controller方法时的调用栈,从图中可以看出,对于DispatcherServlet而言入口在doService方法。

在这里插入图片描述

2.1 doService

  • doService方法是DispatcherServlet类被调用的入口方法,省略部分日志代码,注释如下:
    //做属性处理,委托给doDispatch做实际的调度,
    @Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map<String, Object> attributesSnapshot = null;
		//1.请求对象包含javax.servlet.include.request_uri属性时,进去执行该逻辑,调试时不进入,不关注
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
		//2.使框架对象可用于处理程序并查看对象,传进去一些对象和策略组件,
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
        
        //3.FlashMap、重定向相关
		if (this.flashMapManager != null) {
			FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
			if (inputFlashMap != null) {
				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
			}
			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}

		try {
		    //4.请求处理
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

2.2 doDispatch

  • doDispatch是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 {
			    //1.转换成multipart request,检查是否为上传文件的请求
				processedRequest = checkMultipart(request);
				//2.标记一下是否经过转换
				multipartRequestParsed = (processedRequest != request);
				
				//3.获取HandlerExecutionChain处理器执行链对象
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
				    //没有handler返回404
					noHandlerFound(processedRequest, response);
					return;
				}

				//4.根据请求处理器获取到执行适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				//5.处理LastModified请求头
				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;
					}
				}

                //6.如果preHandle返回false就直接返回,自定义的拦截器前置方法会被调用
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				//7.真正的调用处理器处理请求,返回示图对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                //8.是否异步处理
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
                
                //9.示图处理,返回具体的View
				applyDefaultViewName(processedRequest, mv);
				
				//10.处理后置方法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);
			}
			//11.结果处理,渲染View填充数据 (将模型数据填充至视图中)
			//如果没有异常会调用拦截器的afterCompletion方法
			//异常处理
			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 {
		    //12.异步相关
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
			    //13.清理multipart request相关使用过的资源
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

2.3 getHandler

  • getHandler获取处理请求的handler,它通过遍历策略属性handlerMappings,一旦找到匹配的HandlerExecutionChain就返回,没有找到则返回null。
	//获取HandlerExecutionChain
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

2.4 handle

  • 第七步的handle方法是 AbstractHandlerMethodAdapter#handle,方法很简单主要是委托给子类RequestMappingHandlerAdapter#invokeHandlerMethod执行
    //AbstractHandlerMethodAdapter#handle
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}
  • AbstractHandlerMethodAdapter的handler方法会委托给子类 RequestMappingHandlerAdapter#invokeHandlerMethod执行,RequestMappingHandlerAdapter内部通过HandlerMethod来反射调用;
    @Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			
			//省略....
            
            //invocableMethod是ServletInvocableHandlerMethod实例,继承自InvocableHandlerMethod,是 HandlerMethod 的子类,这里开始慢慢进入反射的部分
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			
			return getModelAndView(mavContainer, modelFactory, webRequest);
	}
  • 走到ServletInvocableHandlerMethod的invokeAndHandle方法,它是HandlerMethod的子类,可以理解为一个包装了目标对象和参数信息的辅助类,这里可以看到反射的影子
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

        //调用目标方法
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        //省略....
	}
  • 继续 InvocableHandlerMethod#invokeForRequest 又走到父类 InvocableHandlerMethod 的 invokeForRequest 方法,
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        //调用目标方法
		Object returnValue = doInvoke(args);
		
		return returnValue;
	}
  • 最后 InvocableHandlerMethod#doInvoke 终于可以看到调用目标方法
    protected Object doInvoke(Object... args) throws Exception {
		ReflectionUtils.makeAccessible(getBridgedMethod());
		try {
		    //d等价于Method.invoke(Object,args)
			return getBridgedMethod().invoke(getBean(), args);
		}
		catch (IllegalArgumentException ex) {
            //各种异常处理,省略...
		}
	}
	
这里getBridgedMethod()会得到一个Method对象,然后Method.invoke(Object,args);
里面的getBean()调用的就是父类的HandlerMethod里面封装的Bean,其实就是我们的目标Bean,args就是方法参数
  • 上述调用栈一路进去比较深,后续可以参考:05-HandlerMethod

2.5 processDispatchResult

  • processDispatchResult处理结果,里面会处理异常、根据异常处理示图、调用拦截器的 afterCompletion方法等
    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

        //1.有异常的情况
		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
			    //2.赋值异常
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		//3.数据渲染 根据View进行渲染视图(即将模型数据填充至视图中)。
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}
        //4.调用 afterCompletion方法
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

三、小结

  • 主要梳理了DispatcherServlet调度处理一个请求的流程,总结如下:
1.通过 HandMapping 策略集合得到执行器链HandlerExecutionChain
2.将HandlerExecutionChain包装成Adapter
3.执行preHandle
4.Adapter返回ModeView
5.ModeView处理得到View
6.后置postHandle调用
7.3-6如果有异常,处理异常
8.渲染View,填充数据
9.afterCompletion方法调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值