SpringMVC源码分析
1、web.xml配置文件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <servlet> <servlet-name>SpringMVC</servlet-name> <servlet- class >org.springframework.web.servlet.DispatcherServlet</servlet- class > // 加载指定位置的SpringMVC的配置文件,如果不设置就默认加载/WEB-INF/<servlet-name>的值-servlet.xml // 默认配置文件路径和名称是: /WEB-INF/SpringMVC-servlet.xml <init-param> <param-name>contextConfigLocation</param-name> // 这里指定了加载的SpringMVC的配置文件路径和名称,就不使用默认的SpringMVC配置文件 <param-value>classpath:SpringMVC.xml</param-value> </init-param> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> // 两个<servlet-name>标签中的值必须一样,框架利用反射获取相对应的Servlet <servlet-name>SpringMVC</servlet-name> // 缺省的路径配置 <url-pattern>/</url-pattern> </servlet-mapping> |
2、启动项目时,初始化SpringMVC相关的组件
1 2 3 4 5 6 7 8 9 10 11 12 | // 项目启动初始化spring相应的组件 protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } |
3、浏览器发送请求,请求被DispatcherServlet拦截之后,Dispatcher调用doDispatch(...)方法进行处理,doDispatch(...)方法源码如下,(不重要的我这里删除了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // 获取当前请求的处理器执行链,里面封装了控制器中的处理方法和拦截器相关信息 mappedHandler = getHandler(processedRequest); if (mappedHandler == null ) { noHandlerFound(processedRequest, response); return ; } // mappedHandler.getHandler()方法获取到的是控制器中处理方法的相应信息,也就是与拦截器分离了 // 通过控制器中处理方法相关的信息获取到处理器适配器,处理器适配器的作用就是调用和执行控制器中与请求对应的处理方法并且获得ModelAndView对象 HandlerAdapter ha = 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 ; } } // 只要有一个拦截器的PreHandle()方法返回值为false,那么mappedHandler.applyPreHandle()的 // 返回值就为false,程序直接return,不会往下继续执行. 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); // 通过处理器执行链和ModelAndView对象进行赋值和视图渲染,视图跳转等操作 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } |
4、mappedHandler = getHandler(processedRequest)
1 2 3 4 5 6 7 8 9 10 11 12 13 | protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if ( this .handlerMappings != null ) { for (HandlerMapping mapping : this .handlerMappings) { // 获取处理器执行链对象(HandlerExecutionChain ),里面封装了Controller层处理器相对应的处理方法和所有的拦截器 // (默认的拦截器ConversionServiceExposingInterceptor、自定义的拦截器MyInterceptor01、MyInterceptor02、MyInterceptor03) HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null ) { return handler; } } } return null ; } |
5、HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()):获取处理器适配器,其作用是为了获取ModelAndView对象,里面封装了Model和View
6、mappedHandler.applyPreHandle(processedRequest, response):对拦截器进行处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // applyPreHandle方法是正向遍历所有的拦截器 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for ( int i = 0 ; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; // 如果拦截器的preHandle()方法返回值是true,那么它会调用下一个拦截器的preHandle()方法 // 如果某一个拦截器的preHandle()方法返回值为false,那么执行完该拦截的preHandle()方法之后 // 它便会去调用triggerAfterCompletion(...)方法,并且整个applyPreHandle()方法的返回值为false. if (!interceptor.preHandle(request, response, this .handler)) { triggerAfterCompletion(request, response, null ); // 只要有一个拦截器的preHandle(...)方法返回值为false,那么整个applyPreHandle(...)方法的返回值为false return false ; } // interceptorIndex的初始值为-1,如果有一个拦截器的返回值为true,interceptorIndex加1,有两个就加2 this .interceptorIndex = i; } } return true ; } |
7、当interceptor.preHandle(request, response, this.handler)的返回值为false(也就是自定义拦截器 return false)时才会调用triggerAfterCompletion(....)方法,然后程序return,结束执行
1 2 3 4 5 6 7 8 | public class MyInterceptor01 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println( "MyInterceptor01--------preHandle01" ); return true ; } } |
8、triggerAfterCompletion(...)方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { // 比如总共有三个拦截器,第一个和第二个拦截器的返回值为true,第三个拦截器的返回值为false,那么interceptrorIndex的值为1 // 表示从最后第二个拦截器开始逆向遍历,第二个拦截器调用它的afterCompletion()方法,然后是第一个拦截器调用它的afterCompletion()方法. for ( int i = this .interceptorIndex; i >= 0 ; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this .handler, ex); } catch (Throwable ex2) { logger.error( "HandlerInterceptor.afterCompletion threw exception" , ex2); } } } } |
9、当interceptor.preHandle(request, response, this.handler)的返回值为true(也就是所有自定义拦截器 return true)时,接着获取ModelAndView对象
通过处理器执行链获的ModelAndView对象
1 | mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); |
10、调用控制器中与请求能匹配的对应的处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Controller public class TestInterceptorsController { @RequestMapping (value = "/testInterceptors" , method = RequestMethod.GET) public String test01(Map<String, Object> map) { map.put( "username" , "xiao mao mao" ); System.out.println( "xiao mao mao bian shen!!!" ); return "loginForm" ; } } |
11、执行mappedHandler.applyPostHandle(processedRequest, response, mv)方法
1 2 3 4 5 6 7 8 9 10 | void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); // 倒序遍历所有的拦截器,所以各个拦截器的postHandle()执行顺序和preHandle()方法是相反的 if (!ObjectUtils.isEmpty(interceptors)) { for ( int i = interceptors.length - 1 ; i >= 0 ; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this .handler, mv); } } } |
12、执行processDispatchResult(...)方法,这个方法很关键,它的主要作用是控制往域对象中存放数据以及视图跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private void processDispatchResult(...) throws Exception { boolean errorView = false ; // 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 ; } // render(mv,request,response)方法执行完毕之后,一定会调用拦截器的triggerAfterCompletion(...)方法 if (mappedHandler != null ) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null ); } } |
13、render(mv,request,response)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { View view; String viewName = mv.getViewName(); if (viewName != null ) { // 渲染视图(解析View对象,由于我们web.xml中配置的是InternalResourceView,所以就由它来解析 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; } } |
14、解析视图名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { Object cacheKey = getCacheKey(viewName, locale); View view = this .viewAccessCache.get(cacheKey); if (view == null ) { synchronized ( this .viewCreationCache) { view = this .viewCreationCache.get(cacheKey); if (view == null ) { // 调用子类创建视图 view = createView(viewName, locale); if (view == null && this .cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null && this .cacheFilter.filter(view, viewName, locale)) { this .viewAccessCache.put(cacheKey, view); this .viewCreationCache.put(cacheKey, view); } } } } else { if (logger.isTraceEnabled()) { logger.trace(formatKey(cacheKey) + "served from cache" ); } } return (view != UNRESOLVED_VIEW ? view : null ); } } |
15、调用子类创建视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | protected View createView(String viewName, Locale locale) throws Exception { if (!canHandle(viewName, locale)) { return null ; } // 视图名称是否以 redirect:开头 if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); String[] hosts = getRedirectHosts(); if (hosts != null ) { view.setHosts(hosts); } return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); } // 视图名称是否以 forward:开头 if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); InternalResourceView view = new InternalResourceView(forwardUrl); return applyLifecycleMethods(FORWARD_URL_PREFIX, view); } // 如果不满足上面的条件,回调父类的createView方法 return super .createView(viewName, locale); } |
16、父类createView方法
1 2 3 | protected View createView(String viewName, Locale locale) throws Exception { return loadView(viewName, locale); } |
1 2 3 4 5 6 | protected View loadView(String viewName, Locale locale) throws Exception { // 构建视图 AbstractUrlBasedView view = buildView(viewName); View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | protected AbstractUrlBasedView buildView(String viewName) throws Exception { Class<?> viewClass = getViewClass(); Assert.state(viewClass != null , "No view class" ); AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass); // 视图Url是我们配置的视图解析器(InternalResourceViewResolver的前缀+视图名+InternalResourceViewResolver的后缀 view.setUrl(getPrefix() + viewName + getSuffix()); view.setAttributesMap(getAttributesMap()); String contentType = getContentType(); return view; } |
17、处理模型数据,获得转发器,以及转发视图
1 2 3 4 5 6 7 8 9 10 11 | public void render( @Nullable Map<String, ?> model, HttpServletRequest request,HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug( "View " + formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + ( this .staticAttributes.isEmpty() ? "" : ", static attributes " + this .staticAttributes)); } Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); } |
18、exposeModelAsRequestAttributes(Map<String,Object> model,HttpServletRequest request)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | exposeModelAsRequestAttributes(Map<String, Object> model,HttpServletRequest request) protected void renderMergedOutputModel (Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // 将Model对象放入请求的域中 exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. exposeHelpers(request); // 获得转发器 String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null ) { throw new ServletException( "Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!" ); } // If already included or response already committed, perform include, else forward. if (useInclude(request, response)) { // 设置响应的类型 response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug( "Including [" + getUrl() + "]" ); } rd.include(request, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. if (logger.isDebugEnabled()) { logger.debug( "Forwarding to [" + getUrl() + "]" ); } // 转发属性,实际上就是 request.getDispatcher("/jsp/mainForm.jsp").forward(request,reponse) rd.forward(request, response); } } |
19、exposeModelAsRequestAttributes(model, request);
1 2 3 4 5 6 7 8 9 10 11 12 | protected void exposeModelAsRequestAttributes(Map<String, Object> model,HttpServletRequest request) throws Exception { model.forEach((name, value) -> { if (value != null ) { // 往请求域中设置值 request.setAttribute(name, value); } else { // 移除请求域中的属性 request.removeAttribute(name); } }); } |
20、处理完了模型,视图以及完成了视图的转发之后,最后执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private void processDispatchResult(...) throws Exception { boolean errorView = false ; // 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 ; } // render(mv,request,response)方法执行完毕之后,一定会调用拦截器的triggerAfterCompletion(...)方法 if (mappedHandler != null ) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null ); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?