Spring MVC的工作原理,我们来看看其源码实现
- 时间:
- 浏览:0
- 来源:大发uu快3_uu快3交流群_大发uu快3交流群
前言
开心一刻
晚上陪老丈人吃饭,另4个劲手机响了,我手贱按了免提……哥们:快出来喝酒!哥哪几条不会呢!我:今天不行,我现在陪老丈人吃饭呢。哥们:那你抓紧喝,我三杯茅台高度酱香酒 ,把我岳父放倒了才出来的,你也快点。看着我老丈人的脸,谁能谁能告诉我该为啥回了……
猪一样的队友
遗留问题图片
在关于利用maven搭建ssm的博客,亲戚亲戚一群人 同時 来探讨下问的最多的问题图片中,我遗留了另4个问题图片:Spring mvc是哪天、何地、怎么都可以 将Model中的属性绑定到哪个作用域,这里的作用域指的是Servlet的四大作用域;不了解问题图片背景的都还可不都可以 回过头去看看我的上篇博文。
明确的解答我会放进去最后,在解答问题图片事先,我先和亲戚亲戚一群人 同時 来捋一捋Spring mvc的工作原理。废话不要 说,结束亲戚亲戚一群人 神秘的探险之旅!
应用示例
在讲工作原理事先,亲戚亲戚一群人 先看另4个简单的spring mvc(ssm)示例,以及实现的效果
工程代码地址:ssm-web
工程特征与效果如上所示,亲戚亲戚一群人 不做不要 的探究,亲戚亲戚一群人 打起精神往下看本篇的重点
工作原理
准备 - 资源的加载与初始化
1、DispatcherServlet 静态初始化
DispatcherServlet含高如下静态块
static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } }
这里会将DispatcherServlet.properties中的内容读取到DispatcherServlet的属性:private static final Properties defaultStrategies中,DispatcherServlet.properties内容如下
指定了DispatcherServlet策略接口的默认实现,后续DispatcherServlet初始化策略的事先会用到
2、interceptor定义的加载
spring启动过程中会调用InterceptorsBeanDefinitionParser的parse辦法 来解析出亲戚亲戚一群人 自定义的interceptor定义,封装成MappedInterceptor类型的bean定义,并放进去spring容器中;亲戚亲戚一群人 都还可不都可以 简单的认为spring容器中机会位于了亲戚亲戚一群人 自定义的interceptor的bean定义
3、DispatcherServlet初始化策略:initStrategies
DispatcherServlet的继承图如下
DispatcherServlet是另4个Servlet,tomcat启动过程中会调用其init辦法 ,一串的调用后,会调用DispatcherServlet的initStrategies辦法
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
实例化步骤1中的默认实现,并填充到DispatcherServlet各个属性值中
4、DefaultAnnotationHandlerMapping的拦截器初始化
DispatcherServlet.properties种指定了另4个默认的HandlerMapping:BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping,这两者的类继承图如下(亲戚亲戚一群人 暂时只关注DefaultAnnotationHandlerMapping)
DefaultAnnotationHandlerMapping间接实现了ApplicationContextAware,没有 在DefaultAnnotationHandlerMapping实例初始化过程中,会调用setApplicationContext(ApplicationContext applicationContext)辦法 ,一串调用后,会来到AbstractUrlHandlerMapping的initApplicationContext()
@Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.mappedInterceptors); initInterceptors(); }
初始化了DefaultAnnotationHandlerMapping的拦截器:interceptor
亲戚亲戚一群人
来看下具体的初始化过程,看看上面的顺序是不是
却说我当时人的臆想?
都还可不都可以 看完,初始化顺序却说亲戚亲戚一群人 上面说的,不会我当时人的意淫;此时的DefaultAnnotationHandlerMapping含高亲戚亲戚一群人 自定义的MyInterceptor。初始化过程亲戚亲戚一群人 需要关注的却说上述那先 ,下面亲戚亲戚一群人 同時 看看具体请求的过程
请求的防止
请求从servlet的service结束,一路到DispatcherServlet的doDispatch,如下图
doDispatch
/** * Process the actual dispatching to the handler. 将请求埋点到具体的handler,也却说亲戚亲戚一群人 的controller * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ 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; // Determine handler for the current request. 决定哪个handler来防止当前的请求 // mappedHandler是由handler和interceptor集合组成的另4个执行链,有点儿相似于FilterChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. 决定哪个adapter来防止当前的请求 // handlerMapping是找出适配的handler,而真正回调handler的是adapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // handler的前置防止,也却说调用适配当前url的interceptor的preHandler辦法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. 真正调用handler mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); // handler的后置防止,也却说调用适配当前url的interceptor的postHandler辦法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } // 防止handler返回的结果,会调用适配当前url的interceptor的afterCompletion辦法 // 这里会将响应结果返回给请求者 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
handlerMapping具体怎么都可以 找到匹配当前url的handler(一般而言却说亲戚亲戚一群人 的controller)、handlerAdapter具体怎么都可以 回调真正的handler,有兴趣的都还可不都可以 自行去跟下,让他不跟了。亲戚亲戚一群人 具体看下processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); 这些 与亲戚亲戚一群人 最初的问题图片有关
processDispatchResult
都还可不都可以 看完model中的persons会被设置到request的attributes中,却说转发请求到show_person.jsp,转发过程中request作用域的变量仍然有效,某些某些show_person.jsp中的jstl标签和el表达式都都还可不都可以 取到persons变量,最后将show_person.jsp中的内容填充好事先的静态内容返回给请求者;至此就完成了一次请求的响应
问题图片解答
回到亲戚亲戚一群人 开篇的问题图片:Spring mvc是哪天、何地、怎么都可以 将Model中的属性绑定到哪个作用域?想必亲戚亲戚一群人 机会知道答案了
Controller中的model、ModelMap的注入由spring mvc完成,这些 不会请求传入的参数,用于绑定变量到Servlet作用域;默认情况汇报下,在DispatcherServlet调用了真正的handler事先,将结果返回给请求者的过程中,将model、modelMap中的变量设置到了request的attributes中,转发的过程中,request中的变量仍然有效,某些某些show_person.jsp中能取到persons这些 变量,自此问题图片得到解答
总结
1、Spring MVC工作原理图
图是用的别人的,具体是谁的我却说记得了(捂脸)
2、DefaultAnnotationHandlerMapping在spring3.2中被废弃,替加进去了RequestMappingHandlerMapping