SpringMvc

本文详细解析了Spring MVC的工作原理,从web.xml配置入手,介绍了DispatcherServlet的初始化过程及请求处理流程,包括国际化资源解析、处理适配器选择等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先还是从disPatchServlet出发,这个类是最底层的类

首先我们在web.xml配置Servlet

<!--servlet配置-->
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext-*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

然后,我们看下disPatchServlet的结构图

104336_4Gtf_2663859.png

可以看出顶层的类是Servlet,学习过Servlet都知道,Servlet里面有

void init(ServletConfig var1) throws ServletException;

ServletConfig getServletConfig();

void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

String getServletInfo();

void destroy();

这几个方法,其中init()方法是在web容器(这里就是Servlet容器,tomcat其实就是一个Servlet容器),在disPatchServlet对应是实现

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

这个方法在tomcat启动的时候加载,这个初始化策略方法帮我们做了一下几件事情,

1、初始化"文件类型解析器",实现是通过应用上下文来获取的,开始是获取默认的解析器

this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);

看getBean的方法

<T> T getBean(String var1, Class<T> var2) throws BeansException;

从这里其实我们可以看出来,是用反射的形式来初始化multipartResolver的(class.newInstance())

2、初始化"国际化资源解析器",这个主要是对国际化的支持的一个类

3、初始化"主题解析器",实现页面风格的类

4、初始化"处理映射器",这个类相当重要,在SpringMVC启动完成时,路径 - 方法,是作为key -value的形式放在Map里面(注意,假如你在调试的过程中,你会发现SpringMvc没有初始化key-value的方法,是在RequestHandlerMapper,其实是Spring先启动把配置文件的bean先注入,所有你调试SpringMvc的时候,不要觉得很奇怪)

111756_hSc8_2663859.png

5、初始化"处理适配器",这个类也相当重要,这个类的主要作用是通过何种适配器来进行工作处理的,在SpringMvc中有4中适配器,一般我们都是用RequestMappingHandlerAdpter作为处理

113818_vDXC_2663859.png

6、初始化"异常处理解析器",这个是专门用来处理发生异常的时候,该怎么处理,它只有下面这个方法,我们可以对它进行功能扩展.

ModelAndView resolveException(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

7、初始化"请求视图名转换器",如果没有返回视图时,默认用这个转换器给默认的视图名称

8、初始化"视图解析器",完成对视图的解析功能,得到一个正在的视图对象

9、初始化"数据保存管理器",对于重定向的参数保存,是通过flashMapManager来保存的

==========以上是tomcat启动,springMvc初始化的一个过程================

对于,我们请求,一般我们是调用Servlet的service()方法,disPatchServlet里面的实现类是

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
      logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
            " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
   }

   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // Make framework objects available to handlers and view objects.
   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());

   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);

   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);
         }
      }
   }
}

通过以上可以看出,这个方法为我们request封装了很多类型,也就是我们前面初始化的一些类型,有了这些东西,我们就可以直接通过request拿出来使用(你会发现SpringMvc使得我们的工作变得多么简单,基本上有些东西就可以拿出来直接使用),真正的实现部分是在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 {
      ModelAndView mv = null;
      Exception dispatchException = null;

      try {
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
         mappedHandler = getHandler(processedRequest, false);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         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()) {
               logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
            }
            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(request, mv);
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      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
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

这里比较重要的几个对象HandlerExecutionChain、ModelAndView、HandlerAdapter

我们来详细解释一下这个方法的执行,首先

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

获取路径映射的方法,如果没有发现的话,返回404

mappedHandler = getHandler(processedRequest, false);

如果找到了方法路径,则获取处理映射的适配器(默认是requestMappingHandlerAdapter)

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

最为重要的是下面这个方法,通过适配器,我们直接反射的形式调用目标方法和参数注入,处理完成后返回一个ModelAndView对象

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

处理拦截器的后置方法,如果我们集成了这个拦截器HandlerInterceptor,那么处理完成后进入postHandle()这个方法

mappedHandler.applyPostHandle(processedRequest, response, mv);

处理请求后的结果

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

=============以上是大概的一个流程,里面的细节大家可以自己去研究================

 

转载于:https://my.oschina.net/chenping12/blog/889267

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值