springmvc最简单配置的解析(4)-----------【springmvc源码】

接着来继续解开我们一开始的疑问:DispatcherServlet为什么是唯一的入口呢?它是如何被设计为唯一入口的?这就是我所抱有的疑问,为什么。。。

 

进过三篇文章的了解,我们是不是也对doDispatch这个方法有了一个新的认识。

那么,你有没有注意到在这个非常重要的方法中有两个异常处理,而且是嵌套的。有想过它为什么这样设计吗?

 

我们了解下这两个异常处理的作用,第一个异常是处理渲染页面抛出,第二个异常也就是内部异常,它把执行请求处理时的异常设置到dispatchException变量,然后在proccessDispatchResult方法中进行处理。而外层异常则处理processDispatchResult方法抛出的异常。

 

那么我们看下processDispatchResult方法。

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

		// 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) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

观察上面的代码,我们可以看到其实它处理异常的方式就是将相应的错误页面设置到View中。而它的渲染页面在render方法中执行。

 

 

接着看下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) {
				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是首先对response设置了Local,过程中使用到了LocalResolver,然后判断View如果是String类型则调用resolveViewName方法使用ViewResolve得到实际的View,最后调用View的render方法对页面进行具体渲染,渲染过程中使用到了ThemeResolver。

 

 

好了,到了这里,我们返回上一个方法processDispatchResult,接着render下去。

最后到了通过mappedHandler的triggerAfterCompletion方法触发Interceptor的afterCompletion方法,注意这里的Interceptor也是按反方向执行的。

 

 

接着返回上一个方法doDispatch,到了finally方法块。这里也就是判断是否请求异步处理,如果启动了则调用相应异步处理的拦截器,否则如果是上传请求则删除上传请求过程中产生的临时资料。

到了这里,我们的doDispatch的处理流程也就讲完了。我们也看到Spring MVC的处理方式是先在顶层设计好整体结构,之后将具体的处理交给不同的组件具体去实现。

 

那么到了这里,我们也就走完了两个嵌套循环。你是否发现了什么呢?

渲染页面、执行请求。。。

我们看下doDispatch的执行过程吧,

 

我们了解到嵌套的异常处理是由内向外的,也就是说代码是有顺序性。至于其他的考虑因素应该也有,但奈何知识浅薄,只能分析到此。

 

 

好了,到了这里,我们已经分析完了doDispatch。但是我们的疑问:DispatcherServlet为什么是唯一的入口呢?它是如何被设计为唯一入口的?这就是我所抱有的疑问,为什么。。。

我们解开了吗。。。

 

 

如果那里不对希望多多指教,不胜感激。

 

参考资料:

看透springmvc源代码分析与实践   第10章  Spring MVC之用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值