DispatcherDervlet类中重点方法讲解

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 mavDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = mavDefiningException.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?
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			// Exception (if any) is already handled..
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

这是一个处理HTTP请求分发结果的方法,通常在Spring MVC的框架内部使用。我将逐步解释这段代码的功能和逻辑。

  1. 方法定义:
    processDispatchResult:方法名,表示处理分发结果。
    它接收以下参数:
    HttpServletRequest request:HTTP请求对象。
    HttpServletResponse response:HTTP响应对象。
    HandlerExecutionChain mappedHandler:一个可能包含处理器(handler)及其拦截器(interceptors)的链。可能是null。
    ModelAndView mv:一个包含模型和视图的对象,用于渲染响应。也可能是null。
    Exception exception:在请求处理过程中可能抛出的异常。可能是null。

  2. 异常处理:
    如果exception不为null,说明在请求处理过程中发生了异常。
    如果异常是ModelAndViewDefiningException的实例,则记录一个debug日志,并从异常中获取ModelAndView对象。
    如果不是ModelAndViewDefiningException,则调用processHandlerException方法来处理异常,并尝试获取一个ModelAndView对象。如果该方法返回了非null的ModelAndView,则errorView被设置为true。

  3. 视图渲染:
    如果mv不为null且没有被清除(wasCleared()返回false),则调用render方法来渲染该视图。
    如果这是一个错误视图(即errorView为true),则清除与错误请求相关的属性。
    如果mv为null或已被清除,则记录一个trace日志,表示没有视图需要渲染。

  4. 并发处理检查:
    使WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()检查是否已开始并发处理。如果是,则方法直接返回,不执行后续操作。

  5. 触发后处理:
    如果mappedHandler不为null,则调用其triggerAfterCompletion方法,该方法可能被用于触发一些在请求完成后需要执行的操作(如清理资源等)。注意,这里传递的最后一个参数是null,表示没有异常需要处理(因为异常已经在之前被处理了)。

  6. 总结
    这个方法主要用于处理HTTP请求的分发结果,包括异常处理、视图渲染和触发后处理等操作。它在Spring MVC的框架内部使用,帮助开发者更方便地处理HTTP请求和响应。

第二个方法render
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.isTraceEnabled()) {
			logger.trace("Rendering view [" + view + "] ");
		}
		try {
			if (mv.getStatus() != null) {
				request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
				response.setStatus(mv.getStatus().value());
			}
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "]", ex);
			}
			throw ex;
		}
	}

这段代码是一个render方法的实现,它在Spring MVC中通常用于将ModelAndView对象渲染到HTTP响应中。以下是对该方法的详细解释:

  1. 确定和设置请求的区域设置(Locale):
    代码首先尝试从localeResolver(如果存在)中解析请求的区域设置。如果不存在localeResolver,则使用请求本身提供的区域设置。
    一旦确定了区域设置,它就被设置到HTTP响应中。

  2. 解析视图:
    从ModelAndView对象中获取视图名称(viewName)。
    如果视图名称不为空,则调用resolveViewName方法来解析视图。这个方法会根据视图名称、模型、区域设置和请求来查找并返回相应的View对象。
    如果resolveViewName返回null,则抛出一个ServletException,表示无法解析该视图名称。
    如果视图名称为空,则直接从ModelAndView对象中获取View对象。如果View对象也为空,则同样抛出一个ServletException。

  3. 渲染视图:
    在渲染之前,如果ModelAndView对象中指定了HTTP状态码,那么将状态码设置到请求和响应中。
    调用View对象的render方法来渲染视图。该方法将模型数据、HTTP请求和HTTP响应作为参数,并实际执行渲染操作。

  4. 异常处理:
    如果在渲染过程中发生异常,首先检查日志级别是否允许调试输出,如果是,则记录异常和相关的视图信息。
    然后重新抛出该异常,以便调用者可以处理它。

  5. 日志记录:
    在渲染视图之前,如果日志级别允许跟踪输出,则记录正在渲染的视图信息。
    这个render方法是Spring MVC框架内部处理请求和响应的关键部分之一。它负责将模型数据渲染到特定的视图中,并将结果发送回客户端。通过这种方法,开发人员可以将控制器逻辑与视图逻辑分离,从而提高应用程序的可维护性和可扩展性。

第三个方法
@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;
	}

这段代码是一个名为 resolveViewName 的方法,它在Spring MVC中通常用于解析视图名称以找到对应的View对象。这个方法通常在DispatcherServlet或其他处理HTTP请求并需要渲染视图的组件中被调用。以下是该方法的详细解释:

  1. 方法签名:
    @Nullable:这是一个注解,表明这个方法可能返回null。这对于调用这个方法的代码来说是一个有用的提示,因为调用者需要知道他们可能需要检查返回值是否为null。
    protected:这是一个访问修饰符,表示这个方法只能在同一个包内或其子类中被访问。
    View:这是返回类型,表示该方法将返回一个View对象或null。
    resolveViewName:这是方法名,描述了该方法的主要功能——解析视图名称。
    参数:
    String viewName:要解析的视图名称。
    @Nullable Map<String, Object> model:模型数据,可能包含要传递给视图的变量。尽管在这个方法内部,这个model参数没有被直接使用,但在某些视图解析器实现中,它可能会被用到。
    Locale locale:当前请求的区域设置,它影响视图的解析(例如,根据区域设置选择适当的语言或格式)。
    HttpServletRequest request:当前的HTTP请求对象。尽管这个参数也没有在这个方法内部被直接使用,但在某些复杂的视图解析逻辑中,它可能会被用来获取额外的信息。

  2. 方法体:
    首先,检查this.viewResolvers(一个ViewResolver的集合)是否为null。这个集合包含了应用程序中配置的所有视图解析器。
    如果viewResolvers不为null,则遍历这个集合中的每一个ViewResolver。
    对于每个ViewResolver,调用其resolveViewName方法,传入视图名称和区域设置作为参数。
    如果ViewResolver的resolveViewName方法返回了一个非null的View对象,则立即返回这个View对象。这意味着一旦找到匹配的视图,就不会再检查剩余的视图解析器。
    如果遍历完所有的视图解析器都没有找到匹配的视图,则方法返回null。

  3. 总结: 这个方法通过遍历应用程序中配置的视图解析器来解析给定的视图名称。如果找到匹配的视图,就返回该视图;否则,返回null。这种方法允许在应用程序中配置多个视图解析器,每个解析器都可以根据自己的规则来解析视图名称。

第二个方法
posted @ 2024-07-06 00:12  文采杰出  阅读(1)  评论(0编辑  收藏  举报