SpringMVC---前端控制器以及视图解析源码学习

调用doDispatch()方法处理流程梳理:
       1、getHandler():根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类。
       2、getHandlerAdapter():根据当前处理器类,找到当前类的HandlerAdapter适配器。
       3、使用刚才获取到的适配器利用反射执行目标方法。
       4、目标方法执行后会返回一个ModelAndView对象。
       5、根据ModelAndView的信息转发到具体的页面。


一、前端控制器DispatcherServlet部分

Alt

1、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 {
	            try {
	                ModelAndView mv = null;
	                Object dispatchException = null;
	
	                try {
	                    processedRequest = this.checkMultipart(request);	//检查是否文件上传请求
	                    multipartRequestParsed = processedRequest != request;
	                    mappedHandler = this.getHandler(processedRequest);	//根据请求的URL找到由哪一个控制器去处理
	                    if (mappedHandler == null) {
	                        this.noHandlerFound(processedRequest, response);
	                        return;
	                    }
	
	                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());	//拿到对应控制器的适配器
	                    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;
	                        }
	                    }
	
	                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	                        return;
	                    }
	
	                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());	//适配器将执行后的信息封装成ModelAndView
	                    if (asyncManager.isConcurrentHandlingStarted()) {
	                        return;
	                    }
	
	                    this.applyDefaultViewName(processedRequest, mv);
	                    mappedHandler.applyPostHandle(processedRequest, response, mv);
	                } catch (Exception var20) {
	                    dispatchException = var20;
	                } catch (Throwable var21) {
	                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
	                }
	
	                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);	//转发到对应页面
	            } catch (Exception var22) {
	                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
	            } catch (Throwable var23) {
	                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
	            }
	
	        } finally {
	            if (asyncManager.isConcurrentHandlingStarted()) {
	                if (mappedHandler != null) {
	                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
	                }
	            } else if (multipartRequestParsed) {
	                this.cleanupMultipart(processedRequest);
	            }
	
	        }
	    }
2、getHandler(processedRequest):

       得到请求与控制器的映射关系。

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	        if (this.handlerMappings != null) {
	            Iterator var2 = this.handlerMappings.iterator();
	
	            while(var2.hasNext()) {
	                HandlerMapping mapping = (HandlerMapping)var2.next();
	                HandlerExecutionChain handler = mapping.getHandler(request);	//递归查找
	                if (handler != null) {
	                    return handler;		//说明前端传过来的URL和注解上的路径匹配, 就返回对应的控制器
	                }
	            }
	        }
	
	        return null;
	    }

       HandlerMapping(九大组件初始化的时候就有值了)中存放的Object:

AltAlt

3、getHandlerAdapter(mappedHandler.getHandler()):

       得到请求与目标方法的映射关系。

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	        if (this.handlerAdapters != null) {
	            Iterator var2 = this.handlerAdapters.iterator();
	
	            while(var2.hasNext()) {
	                HandlerAdapter adapter = (HandlerAdapter)var2.next();
	                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");
	    }

       适配器的类型:
Alt

4、ha.handle(processedRequest, response, mappedHandler.getHandler()):

       确定方法运行时的参数,利用反射执行目标方法

       Spring4.0参数确定机制,5.0不太清楚到底是不是这样的,Debug源码太难了,我是个菜鸡啊啊。。。来自尚硅谷LFY大神:
Alt

小结:先根据请求得地址找到对应的控制器类,再找到目标方法的适配器,确定参数并利用反射调用目标方法。




二、视图解析部分

1、processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException):
	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) {
	                this.logger.debug("ModelAndViewDefiningException encountered", exception);
	                mv = ((ModelAndViewDefiningException)exception).getModelAndView();
	            } else {
	                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
	                mv = this.processHandlerException(request, response, handler, exception);
	                errorView = mv != null;
	            }
	        }
	
	        if (mv != null && !mv.wasCleared()) {
	            this.render(mv, request, response);		//渲染页面
	            if (errorView) {
	                WebUtils.clearErrorRequestAttributes(request);
	            }
	        } else if (this.logger.isTraceEnabled()) {
	            this.logger.trace("No view rendering, null ModelAndView returned.");
	        }
	
	        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
	            if (mappedHandler != null) {
	                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
	            }
	
	        }
	    }
2、render(mv, request, response):
	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);
	        String viewName = mv.getViewName();
	        View view;
	        if (viewName != null) {
	            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);	//根据viewName解析得到view
	            if (view == null) {
	                throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
	            }
	        } else {
	            view = mv.getView();
	            if (view == null) {
	                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
	            }
	        }
	
	        if (this.logger.isTraceEnabled()) {
	            this.logger.trace("Rendering view [" + view + "] ");
	        }
	
	        try {
	            if (mv.getStatus() != null) {
	                response.setStatus(mv.getStatus().value());
	            }
	
	            view.render(mv.getModelInternal(), request, response);	//调用View的函数去渲染
	        } catch (Exception var8) {
	            if (this.logger.isDebugEnabled()) {
	                this.logger.debug("Error rendering view [" + view + "]", var8);
	            }
	
	            throw var8;
	        }
	    }
3、resolveViewName(viewName, mv.getModelInternal(), locale, request):
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
	        if (this.viewResolvers != null) {
	            Iterator var5 = this.viewResolvers.iterator();
	
	            while(var5.hasNext()) {
	                ViewResolver viewResolver = (ViewResolver)var5.next();
	                View view = viewResolver.resolveViewName(viewName, locale);	//得到view, 这个东西其实是九大组件之一
	                if (view != null) {
	                    return view;
	                }
	            }
	        }
	
	        return null;
	    }

Alt       当视图解析器为空的时候Spring4.0会用默认的InternalResourceViewResolver视图解析器

扫描二维码关注公众号,回复: 9190231 查看本文章

       SpringMVC有不同的视图解析器,4.0版本返回的viewName中带有redirect或forward前缀的时候,会新建对应的视图对象非这两个前缀的话都会带上国际化信息并用InternalResourceViewResolver拼接URL

4、view.render(mv.getModelInternal(), request, response):

       运行时确定是哪个View,将数据保存到隐含模型中。
       SpringMVC4.0隐含模型保存参数的确定机制,5.0不太清楚到底是不是这样的,来自尚硅谷LFY大神:
Alt

小结:视图解析器只是为了得到视图对象;视图对象才能真正的转发或者重定向到页面并渲染视图。



总结:学到现在,个人感觉SpringMVC牛逼的一个地方在于隐含模型,每次请求都会在request域中放值到隐含模型中,真的太强了。

发布了33 篇原创文章 · 获赞 5 · 访问量 2283

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/104044218
今日推荐