spring mvc 启动+运行原理
纯文本描述,时间有限,就不再另行搞图了,以后如果有需要再补充就是,现在本地版的Visual Paradigm还用不熟,processon的话也可以画,到时候看如果说以后需要培训新人或者做技术共享的时候再补充吧
注意:我这边大部分的博客都是为了记录给自己看的,并非为了让大家能一眼看明白,毕竟这玩意不是写几百个字就能说明白的。
说到Spring跳脱不开IOC和AOP。这边MVC主要牵扯到的也就是IOC
在整个IOC的启动过程中,真正用来初始化MVC构建的是一个监听器事件,直接看截图吧,这里是在IOC的refresh方法执行快结束的时候触发(AbstractApplicationContext->refresh->finishRefresh->publishEvent(new ContextRefreshedEvent(this)))
最终到了下面这个方法:
先看一下类图吧
简单来说就是FrameworkServlet是DispatcherServlet(这个类要是不知道,那也不用看Spring MVC了)的父类
继续看里面的方法
大概解释下:
/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { // 上传文件用的 initMultipartResolver(context); // 国际化 initLocaleResolver(context); // 主题渲染 initThemeResolver(context); // 请求映射 initHandlerMappings(context); // 处理适配器,连接处理器和视图的,就是View and Action,比如说调用完了action之后将输出转化为视图 initHandlerAdapters(context); // 异常处理解析 initHandlerExceptionResolvers(context); // 视图名称转化,看里面的接口,实现的是前后缀组装,比如说传入的是 /index.html,可以转化为 /view/index.ftl initRequestToViewNameTranslator(context); // 视图渲染,比如ThymeleafViewResolver和FreeMarkerViewResolver initViewResolvers(context); // 快照Map,这个可以参考RequestMappingHandlerAdapter->getModelAndView里面有个对跳转的处理需要获取FlashMap initFlashMapManager(context); }
这里面的方法点进去执行的逻辑都差不多,就看一个,请求映射的,基本上都是初始化对应的策略、排序,没有的话就从默认取或初始化。
/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerMappings declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } } }
初始化基本上就是流程
运行的时候
1、入口:HttpServlet(service)->FrameworkServlet(service)->processRequest->DispacherServlet(doService)->dispacher
2、大致流程
/** * Process the actual dispatching to the handler. * <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. // 获取一个处理器,并包裹进一个处理器链,里面主要是Controller对象和一堆拦截器 mappedHandler = getHandler(processedRequest); // 匹配不到处理器的情况 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // 获取一个适配器,将上面获取的处理器对应的实际controller包裹进去,适合用于扩展 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 调用前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // 调用适配器的处理,主要业务逻辑也在这里执行,方法比较复杂 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 如果没有视图名称的话,设置一个默认的,一般是请求名 applyDefaultViewName(processedRequest, mv); // 调用后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 对返回结果进行处理,比如视图的渲染 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } // 理资源释放 finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
比较复杂的是这行代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
里面涉及了入参的解析获取,实际处理器的方法调用。这个就自己看比较好。