DispatcherServlet 详解

Java知识点总结:想看的可以从这里进入

2.1、DispatcherServlet

DispatcherServlet作为SpringMVC的核心所在,我们需要消息的了解它。它和Servlet相似,内部也是通过 doService 方法处理HTTP请求的,我们可以观看它内部处理的步骤,可以更好的帮助我们理解SpringMVC的整个流程

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);

    // 在包含的情况下保留请求属性的快照,以便能够在包含后恢复原始属性。
    Map<String, Object> attributesSnapshot = null;
    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));
            }
        }
    }

    // 使框架对象可用于处理程序和视图对象。
    //设置WEB IOC容器
    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());

    //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);
    }
    
	//上一个请求路径
    RequestPath previousRequestPath = null;
    if (this.parseRequestPath) {
        previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
        ServletRequestPathUtils.parseAndCache(request);
    }

    try {
        //分发处理,对处理程序的实际调度。将通过依次应用 servlet 的 HandlerMappings 来获取处理程序。
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            //恢复原始属性快照,以防包含
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        if (this.parseRequestPath) {
            ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
        }
    }
}

doService在进行快照处理后,就进行了分发操作 doDispatch(request, response)。此方法将将通过依次应用 servlet 的 HandlerMappings 来获取处理程序。

//处理程序将通过依次应用 servlet 的 HandlerMappings 来获得。 HandlerAdapter 将通过查询 servlet 的已安装 HandlerAdapter 来获得,以找到第一个支持处理程序类的。
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);

				// 确定当前请求的处理程序,以获取相应的执行链,如果没有直接退出
				mappedHandler = getHandler(processedRequest);
                //没有获取到,直接退出
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 获取到了执行链,调用HandlerAdapter适配器。
                //确定当前请求的处理程序适配器(HandlerAdapter)
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 如果处理程序支持,则处理最后修改的标头
                //判断此请求时get、还是post
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
                //是get请求
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				//执行拦截器前的预处理方法,返回false直接结束
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 执行处理器,返回ModelAndView
				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) {
				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()) {on
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

springMVC在一开始就初始化了处理器映射器,并将所有的处理器映射器封装到了 handlerMappings中,它通过遍历获取对应的处理器映射器,并将其封装成HandlerExecutionChain对象,这个对象就是处理程序执行链,由处理程序对象和任何处理程序拦截器组成。

private List<HandlerMapping> handlerMappings;
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;
}

DispatcherServlet获取到了执行链,就应该去找相应的HandlerAdapter去执行这个执行链了,同handlerMapping类似,HandlerAdapter适配器一样也是在启动时被封装到List中,遍历看哪一个适配器支持这个执行链,就返回那个。

private List<HandlerAdapter> handlerAdapters;
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            //看哪一个适配器支持这个执行链
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

适配器执行完成后,得到ModelAndView,就会开始进行视图的解析,

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {

    boolean errorView = false;
	//如果处理器发生了异常
    if (exception != null) {
        //是模型和视图定义异常
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        //处理器异常
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // 处理程序是否返回要渲染的视图
    if (mv != null && !mv.wasCleared()) {
        //进行渲染视图
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        //没有视图渲染,返回 null ModelAndView
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // 在转发期间开始并发处理
        return;
    }

    if (mappedHandler != null) {
        // 异常(如果有)已被处理..
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

根据逻辑视图和真实视图进行不同操作。

//渲染给定的 ModelAndView。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    //确定请求的语言环境并将其应用于响应。国际化
    Locale locale =
        (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);
	
    View view;
    String viewName = mv.getViewName();
    //是否是逻辑视图,如果是则转换成真实视图
    if (viewName != null) {
        // 我们需要解析视图名称,将逻辑视图,转化成真实视图
        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 {
        // 无需查找:ModelAndView 对象包含实际的 View 对象
        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() + "'");
        }
    }

    // 委托给 View 对象进行渲染。
    if (logger.isTraceEnabled()) {
        logger.trace("Rendering view [" + view + "] ");
    }
    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        //渲染视图 mv.getModelInternal()数据模型。view为视图
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "]", ex);
        }
        throw ex;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰 羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值