阅读 205

SpringMvc 工作流程源码分析(简述springmvc框架执行流程)

在分析SpringMvc的第一步,我们首先在testController上添加一个断点,并打开debug,访问当前接口,可以看到SpringMvc在DispatchServlet中开始接收并处理我们的请求,在此之前还有些servlet和filter的处理流程。

DispatcherServlet的初始化

首先我们对DispatcherServlet这个类进行下梳理,查看下它的继承结构 2.PNG 这个类主要是实现了Servlet接口以及ApplicationContextAware接口,ApplicationContextAware的作用是可以方便获取Spring容器ApplicationContext,从而可以获取容器内的Bean。 对于Servlet接口,应该都比较熟悉了,有init,service,destroy以及两个关于设置配置的方法。 对于GenericServlet抽象类,主要是实现了Servlet接口,并且添加了写配置信息以及初始化方法,它的初始化就是保存自己的配置信息之后执行init

public void init(ServletConfig config) throws ServletException {     this.config = config;     this.init(); } public void init() throws ServletException { } 复制代码

HttpServlet 主要是通过doService分派给不同的请求方法的执行方式。 接下来是HttpServletBean的初始化方式

@Override public final void init() throws ServletException {    // Set bean properties from init parameters.    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);    if (!pvs.isEmpty()) {       try {          BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);          ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());          bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));          initBeanWrapper(bw);          bw.setPropertyValues(pvs, true);       }       catch (BeansException ex) {          if (logger.isErrorEnabled()) {             logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);          }          throw ex;       }    }    // 第一次执行会走这里,初始化我们ServletBean的情况    initServletBean(); } ``` protected final void initServletBean() throws ServletException {    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");    if (logger.isInfoEnabled()) {       logger.info("Initializing Servlet '" + getServletName() + "'");    }    long startTime = System.currentTimeMillis();    try {       this.webApplicationContext = initWebApplicationContext();       initFrameworkServlet();    }    catch (ServletException | RuntimeException ex) {       logger.error("Context initialization failed", ex);       throw ex;    }    if (logger.isDebugEnabled()) {       String value = this.enableLoggingRequestDetails ?             "shown which may lead to unsafe logging of potentially sensitive data" :             "masked to prevent unsafe logging of potentially sensitive data";       logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +             "': request parameters and headers will be " + value);    }    if (logger.isInfoEnabled()) {       logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");    } } ``` 复制代码

这段代码的主要功能就是初始化我们WebApplicationCOntext的对象,如下图所示

3.PNG

接下来到了我们DispatcherServlet的初始化

protected void initStrategies(ApplicationContext context) {    initMultipartResolver(context);    initLocaleResolver(context);    initThemeResolver(context);    initHandlerMappings(context);    initHandlerAdapters(context);    initHandlerExceptionResolvers(context);    initRequestToViewNameTranslator(context);    initViewResolvers(context);    initFlashMapManager(context); } 复制代码

DispatcherServlet是通过初始化策略的方式对于所有的常用对象如处理器适配器,处理器映射器,视图解析器,文件上传处理器来进行处理的,并且将这些组件都放置在applicationContest中方便取用.

4.PNG

我们以视图解析器为例,其主要是通过

BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); 复制代码

这个方法来获取和ViewResolver相关的类的,这个方法返回指定类型和子类型的所有bean,若该bean factory 是一个继承类型的beanFactory,这个方法也会获取祖宗factory中定义的指定类型的bean。

到此,DispatcherServlet就完成了对于所有的组件的初始化,基本上是将WebApplicationContext装入我们的IOC容器内,以及Servlet的一些配置属性,最终初始化SpringMVC的常用组件装入到我们的ApplicationCOntext中。

SpringMVC的请求处理过程

首先,我们的请求是会进入到我们doService中的逻辑中来的。

@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {     // 对于我们当前的Request进行一次记录    logRequest(request);    // include是在一个Servlet中嵌入一个Servlet的情况,所以要保存当前Servlet属性的快照    // to be able to restore the original attributes after the include.    Map<String, Object> attributesSnapshot = null;    if (WebUtils.isIncludeRequest(request)) {       attributesSnapshot = new HashMap<>();       Enumeration<?> attrNames = request.getAttributeNames();       while (attrNames.hasMoreElements()) {          String attrName = (String) attrNames.nextElement();          if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {             attributesSnapshot.put(attrName, request.getAttribute(attrName));          }       }    }    // 将handler和viewResolver放入到我们的request中,方便使用    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());    if (this.flashMapManager != null) {       FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);       if (inputFlashMap != null) {          request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));       }       request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());       request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);    }    RequestPath previousRequestPath = null;    if (this.parseRequestPath) {       previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);       ServletRequestPathUtils.parseAndCache(request);    }     // 真正的处理逻辑调用给dispatch    try {       doDispatch(request, response);    }    finally {       if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {          // Restore the original attribute snapshot, in case of an include.          if (attributesSnapshot != null) {             restoreAttributesAfterInclude(request, attributesSnapshot);          }       }       if (this.parseRequestPath) {          ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);       }    } } 复制代码

doService的基本逻辑就是进行一些前期的处理,比如将HandlerMapping,viewResolver封装到我们的request对象中,并且一些属性快照进行保存。

@SuppressWarnings("deprecation") 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);          // 决定当前请求的handler,这个函数的主要逻辑就是看当前handlerMapping中是否有当前的一个request请求对象,返回的是一个HandlerExecutionChain的对象,使用了责任链的设计模式          mappedHandler = getHandler(processedRequest);          if (mappedHandler == null) {             noHandlerFound(processedRequest, response);             return;          }          // 通过Handler为其匹配适配器,采用了适配器的设计模式          HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());          // Process last-modified header, if supported by the handler.          String method = request.getMethod();          boolean isGet = HttpMethod.GET.matches(method);          if (isGet || HttpMethod.HEAD.matches(method)) {             long lastModified = ha.getLastModified(request, mappedHandler.getHandler());             if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {                return;             }          }          if (!mappedHandler.applyPreHandle(processedRequest, response)) {             return;          }          // 通过handlerAdapter来handler的request,会返回一个ModelAndView          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);          }       }    } } 复制代码

最后对整个流程进行一个总结: 1、用户发送请求至前端控制器DispatcherServlet。

2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、Controller执行完成返回ModelAndView。

7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、ViewReslover解析后返回具体View.

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet响应用户。


作者:星海Coding
链接:https://juejin.cn/post/7037665938312790053

 伪原创工具 SEO网站优化  https://www.237it.com/ 


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐