zoukankan      html  css  js  c++  java
  • SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

    SpringMVC在使用过程中,大多是使用注解,对它的实现接口之类的关系理解变得模糊, 通过对XML配置的理解,可以理清各个类的关系,譬如控制器类要实现Controller接口。

    接触SpringMVC,对它的xml文件配置一直比较模模糊糊,最近花了一点时间稍微看了下源代码,再加上调试,开始逐渐理解它,网上的类似的内容有很多,写本文主要是自己加深一下理解。本文适合用过SpringMVC的开发者,言归正传,首先搭建一个最简单的工程体验一下。 

    该工程是基于maven的,pom配置不再说明,所使用的spring版本4.0.5。 
    首先是web.xml文件配置,最简单的配置 

    Java代码  收藏代码
    1. <!DOCTYPE web-app PUBLIC  
    2.  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
    3.  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
    4.   
    5. <web-app>  
    6.   <display-name>Archetype Created Web Application</display-name>  
    7.   <servlet>  
    8.         <servlet-name>mvc</servlet-name>  
    9.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    10.         <load-on-startup>1</load-on-startup>  
    11.     </servlet>  
    12.   
    13.     <servlet-mapping>  
    14.         <servlet-name>mvc</servlet-name>  
    15.         <url-pattern>/*</url-pattern>  
    16.     </servlet-mapping>  
    17. </web-app>  


    然后是mvc-servlet.xml文件的配置,上面配置DispatcherServlet会默认加载[servlet-name]-servlet.xml文件。对于我的配置,会去加载mvc-servlet.xml文件。 
    mvc-servlet.xml文件的内容: 

    Java代码  收藏代码
    1. <?xml version="1.0" encoding="UTF-8" ?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"  
    3.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    4.     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
    5.     http://www.springframework.org/schema/mvc  
    6.     http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  
    7.     http://www.springframework.org/schema/util  
    8.     http://www.springframework.org/schema/util/spring-util-2.0.xsd  
    9.     http://www.springframework.org/schema/context   
    10.     http://www.springframework.org/schema/context/spring-context-3.2.xsd">  
    11.   
    12.     <bean name="/index" class="com.lg.mvc.HomeAction"></bean>  
    13.     <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  
    14.         <property name="templateLoaderPath" value="/WEB-INF/views" />  
    15.         <property name="defaultEncoding" value="utf-8" />  
    16.         <property name="freemarkerSettings">  
    17.             <props>  
    18.                 <prop key="locale">zh_CN</prop>  
    19.             </props>  
    20.         </property>  
    21.     </bean>  
    22.     <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  
    23.         <property name="suffix" value=".html" />  
    24.         <property name="contentType" value="text/html;charset=utf-8" />  
    25.         <property name="requestContextAttribute" value="request" />  
    26.         <property name="exposeRequestAttributes" value="true" />  
    27.         <property name="exposeSessionAttributes" value="true" />  
    28.     </bean>  
    29. </beans>  


    在该配置中定义了一个HomeAction的Bean。内容为: 

    Java代码  收藏代码
    1. package com.lg.mvc;  
    2.   
    3. import javax.servlet.http.HttpServletRequest;  
    4. import javax.servlet.http.HttpServletResponse;  
    5.   
    6. import org.springframework.web.servlet.ModelAndView;  
    7. import org.springframework.web.servlet.mvc.Controller;  
    8.   
    9. public class HomeAction implements Controller{  
    10.   
    11.     @Override  
    12.     public ModelAndView handleRequest(HttpServletRequest request,  
    13.             HttpServletResponse response) throws Exception {  
    14.         return new ModelAndView("hello");  
    15.     }  
    16. }  


    这是最原始的mvc做法,要继承Controller接口,先从原始的说起,最后再过渡到@Controller和@RequestMapping注解式的配置。它在mvc-serlet.xml文件中的配置有一个关键的属性name="/index"。 
    WEB-INF/view目录下有一个简单的hello.html,内容为: 

    Java代码  收藏代码
    1. <html>  
    2.     <head>  
    3.       
    4.     </head>  
    5.     <body>  
    6.         hello lg !  
    7.     </body>  
    8. </html>  


    至此该工程就写完了,部署到tomcat中,项目路径为/,运行一下。 
    访问 http://localhost:8080/index 
     
    至此整个工程就算搭建成功了。 

    下面就要说说原理了。 
    用过python Django框架的都知道Django对于访问方式的配置就是,一个url路径和一个函数配对,你访问这个url,就会直接调用这个函数,简单明了。对于java的面向对象来说,就要分两步走。第一步首先要找到是哪个对象,即handler,本工程的handler则是HomeAction对象。第二步要找到访问的函数,即HomeAction的handleRequest方法。所以就出现了两个源码接口 HandlerMapping和HandlerAdapter,前者负责第一步,后者负责第二步。借用网上的SpringMVC架构图。 

    HandlerMapping接口的实现(只举了我认识的几个) : 

        BeanNameUrlHandlerMapping :通过对比url和bean的name找到对应的对象 
        SimpleUrlHandlerMapping :也是直接配置url和对应bean,比BeanNameUrlHandlerMapping功能更多 
        DefaultAnnotationHandlerMapping : 主要是针对注解配置@RequestMapping的,已过时 
        RequestMappingHandlerMapping :取代了上面一个 


    HandlerAdapter 接口实现: 

        HttpRequestHandlerAdapter : 要求handler实现HttpRequestHandler接口,该接口的方法为                                                             void handleRequest(HttpServletRequest request, HttpServletResponse response)也就是  handler必须有一个handleRequest方法 



        SimpleControllerHandlerAdapter:要求handler实现Controller接口,该接口的方法为ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response),也就是本工程采用的 



        AnnotationMethodHandlerAdapter :和上面的DefaultAnnotationHandlerMapping配对使用的,也已过时 



        RequestMappingHandlerAdapter : 和上面的RequestMappingHandlerMapping配对使用,针对@RequestMapping 


    先简单的说下这个工程的流程,访问http://localhost:8080/index首先由DispatcherServlet进行转发,通过BeanNameUrlHandlerMapping(含有 /index->HomeAction的配置),找到了HomeAction,然后再拿HomeAction和每个adapter进行适配,由于HomeAction实现了Controller接口,所以最终会有SimpleControllerHandlerAdapter来完成对HomeAction的handleRequest方法的调度。然后就顺利的执行了我们想要的方法,后面的内容不在本节中说明。 

    了解了大概流程,然后就需要看源代码了。 
    首先就是SpringMVC的入口类,DispatcherServlet,它实现了Servlet接口,不再详细说DispatcherServlet的细节,不然又是一大堆的内容。每次请求都会调用它的doService->doDispatch,我们关注的重点就在doDispatch方法中。 

    Java代码  收藏代码
    1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    2.         HttpServletRequest processedRequest = request;  
    3.         HandlerExecutionChain mappedHandler = null;  
    4.         boolean multipartRequestParsed = false;  
    5.   
    6.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
    7.   
    8.         try {  
    9.             ModelAndView mv = null;  
    10.             Exception dispatchException = null;  
    11.   
    12.             try {  
    13.                 processedRequest = checkMultipart(request);  
    14.                 multipartRequestParsed = (processedRequest != request);  
    15.                       //这个是重点,第一步由HandlerMapping找到对应的handler  
    16.                 // Determine handler for the current request.  
    17.                 mappedHandler = getHandler(processedRequest);  
    18.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {  
    19.                     noHandlerFound(processedRequest, response);  
    20.                     return;  
    21.                 }  
    22.   
    23.                 // Determine handler adapter for the current request.  
    24.                        //这是第二步,找到合适的HandlerAdapter,然后由它来调度执行handler的方法  
    25.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
    26.   
    27.                 // Process last-modified header, if supported by the handler.  
    28.                 String method = request.getMethod();  
    29.                 boolean isGet = "GET".equals(method);  
    30.                 if (isGet || "HEAD".equals(method)) {  
    31.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
    32.                     if (logger.isDebugEnabled()) {  
    33.                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);  
    34.                     }  
    35.                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
    36.                         return;  
    37.                     }  
    38.                 }  
    39.   
    40.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
    41.                     return;  
    42.                 }  
    43.   
    44.                 try {  
    45.                     // Actually invoke the handler.  
    46.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
    47.                 }  
    48.                 finally {  
    49.                     if (asyncManager.isConcurrentHandlingStarted()) {  
    50.                         return;  
    51.                     }  
    52.                 }  
    53.   
    54.                 applyDefaultViewName(request, mv);  
    55.                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
    56.             }  
    57.             catch (Exception ex) {  
    58.                 dispatchException = ex;  
    59.             }  
    60.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
    61.         }  
    62.         catch (Exception ex) {  
    63.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
    64.         }  
    65.         catch (Error err) {  
    66.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
    67.         }  
    68.         finally {  
    69.             if (asyncManager.isConcurrentHandlingStarted()) {  
    70.                 // Instead of postHandle and afterCompletion  
    71.                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
    72.                 return;  
    73.             }  
    74.             // Clean up any resources used by a multipart request.  
    75.             if (multipartRequestParsed) {  
    76.                 cleanupMultipart(processedRequest);  
    77.             }  
    78.         }  
    79.     }  


    第一步详细查看: 

    Java代码  收藏代码
    1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    2.         for (HandlerMapping hm : this.handlerMappings) {  
    3.             if (logger.isTraceEnabled()) {  
    4.                 logger.trace(  
    5.                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
    6.             }  
    7.             HandlerExecutionChain handler = hm.getHandler(request);  
    8.             if (handler != null) {  
    9.                 return handler;  
    10.             }  
    11.         }  
    12.         return null;  
    13.     }  


    可以看到就是通过遍历所有已注册的HandlerMapping来找到对应的handler,然后构建出一个HandlerExecutionChain,它包含了handler和HandlerMapping本身的一些拦截器,如下 

    Java代码  收藏代码
    1. public class HandlerExecutionChain {  
    2.   
    3.     private final Object handler;  
    4.   
    5.     private HandlerInterceptor[] interceptors;  
    6.   
    7.     private List<HandlerInterceptor> interceptorList;  
    8.           
    9.         //其他代码省略  
    10. }  


    其中HandlerMapping的getHandler实现: 

    Java代码  收藏代码
    1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    2.         Object handler = getHandlerInternal(request);  
    3.         if (handler == null) {  
    4.             handler = getDefaultHandler();  
    5.         }  
    6.         if (handler == null) {  
    7.             return null;  
    8.         }  
    9.         // Bean name or resolved handler?  
    10.         if (handler instanceof String) {  
    11.             String handlerName = (String) handler;  
    12.             handler = getApplicationContext().getBean(handlerName);  
    13.         }  
    14.         return getHandlerExecutionChain(handler, request);  
    15.     }  


    这里的getHandlerInternal(request)是个抽象方法,由具体的HandlerMapping来实现,获取到的handler如果为空,则获取默认配置的handler,如果handler为String类型,则表示这个则会去Spring容器里面去找这样名字的bean。 
    再看下BeanNameUrlHandlerMapping的getHandlerInternal(request)的具体实现(通过一系列的接口设计,之后再好好看看这个设计,到BeanNameUrlHandlerMapping这只用实现该方法中的一部分),如下 

    Java代码  收藏代码
    1. public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {  
    2.   
    3.     /** 
    4.      * Checks name and aliases of the given bean for URLs, starting with "/". 
    5.      */  
    6.     @Override  
    7.     protected String[] determineUrlsForHandler(String beanName) {  
    8.         List<String> urls = new ArrayList<String>();  
    9.         if (beanName.startsWith("/")) {  
    10.             urls.add(beanName);  
    11.         }  
    12.         String[] aliases = getApplicationContext().getAliases(beanName);  
    13.         for (String alias : aliases) {  
    14.             if (alias.startsWith("/")) {  
    15.                 urls.add(alias);  
    16.             }  
    17.         }  
    18.         return StringUtils.toStringArray(urls);  
    19.     }  
    20.   
    21. }  


    这里面注释说,bean的name必须以/开头,它才处理,将信息存储在Map<String, Object> handlerMap中,对于本工程来说就是{'/index':HomeAction对象}。 
    至此这里完成了第一步,下面开始第二步,即方法HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());的具体实现: 

    Java代码  收藏代码
    1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  
    2.         for (HandlerAdapter ha : this.handlerAdapters) {  
    3.             if (logger.isTraceEnabled()) {  
    4.                 logger.trace("Testing handler adapter [" + ha + "]");  
    5.             }  
    6.             if (ha.supports(handler)) {  
    7.                 return ha;  
    8.             }  
    9.         }  
    10.         throw new ServletException("No adapter for handler [" + handler +  
    11.                 "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");  
    12.     }  


    遍历所有的HandlerAdapter,判断他们是否支持这个handler。 
    我们来看下HttpRequestHandlerAdapter的supports(handler)方法: 

    Java代码  收藏代码
    1. public class HttpRequestHandlerAdapter implements HandlerAdapter {  
    2.   
    3.     @Override  
    4.     public boolean supports(Object handler) {  
    5.           //就是判断handler是否实现了HttpRequestHandler接口  
    6.         return (handler instanceof HttpRequestHandler);  
    7.     }  
    8.   
    9.     @Override  
    10.     public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
    11.             throws Exception {  
    12.            //若handler实现了HttpRequestHandler接口,则调用该接口的方法,执行我们在该方法中写的业务逻辑  
    13.         ((HttpRequestHandler) handler).handleRequest(request, response);  
    14.         return null;  
    15.     }  
    16.   
    17.     @Override  
    18.     public long getLastModified(HttpServletRequest request, Object handler) {  
    19.         if (handler instanceof LastModified) {  
    20.             return ((LastModified) handler).getLastModified(request);  
    21.         }  
    22.         return -1L;  
    23.     }  
    24.   
    25. }  


    同理SimpleControllerHandlerAdapter也是这样类似的逻辑 

    Java代码  收藏代码
    1. public class SimpleControllerHandlerAdapter implements HandlerAdapter {  
    2.   
    3.     @Override  
    4.     public boolean supports(Object handler) {  
    5.         return (handler instanceof Controller);  
    6.     }  
    7.   
    8.     @Override  
    9.     public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
    10.             throws Exception {  
    11.   
    12.         return ((Controller) handler).handleRequest(request, response);  
    13.     }  
    14.   
    15.     @Override  
    16.     public long getLastModified(HttpServletRequest request, Object handler) {  
    17.         if (handler instanceof LastModified) {  
    18.             return ((LastModified) handler).getLastModified(request);  
    19.         }  
    20.         return -1L;  
    21.     }  
    22.   
    23. }  


    剩余两个AnnotationMethodHandlerAdapter和RequestMappingHandlerAdapter就比较复杂,我也没看。 
    按照本工程的配置,则SimpleControllerHandlerAdapter是支持HomeAction的,然后就会执行SimpleControllerHandlerAdapter的handle(processedRequest, response, mappedHandler.getHandler())方法。本质上就会调用HomeAction实现Controller接口的方法。至此就分析完了。 
    了解过程了之后,然后就是最重要的也是经常配置出问题的地方。DispatcherServlet的handlerMappings和handlerAdapters的来源问题。 

    DispatcherServlet初始化的时候,会调用一个方法如下: 

    Java代码  收藏代码
    1. protected void initStrategies(ApplicationContext context) {  
    2.         initMultipartResolver(context);  
    3.         initLocaleResolver(context);  
    4.         initThemeResolver(context);  
    5. //初始化一些HandlerMapping  
    6.         initHandlerMappings(context);  
    7. //初始化一些HandlerAdapter  
    8.         initHandlerAdapters(context);  
    9.         initHandlerExceptionResolvers(context);  
    10.         initRequestToViewNameTranslator(context);  
    11.         initViewResolvers(context);  
    12.         initFlashMapManager(context);  
    13.     }  


    这里可以看到,它会初始化一些HandlerMapping和HandlerAdapter,这两个方法非常重要,理解了这两个方法你就会知道,配置不对问题出在哪里,下面具体看下这两个方法: 

    Java代码  收藏代码
    1. private void initHandlerMappings(ApplicationContext context) {  
    2.         this.handlerMappings = null;  
    3.   
    4.         if (this.detectAllHandlerMappings) {  
    5.             // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.  
    6.             Map<String, HandlerMapping> matchingBeans =  
    7.                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);  
    8.             if (!matchingBeans.isEmpty()) {  
    9.                 this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());  
    10.                 // We keep HandlerMappings in sorted order.  
    11.                 OrderComparator.sort(this.handlerMappings);  
    12.             }  
    13.         }  
    14.         else {  
    15.             try {  
    16.                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  
    17.                 this.handlerMappings = Collections.singletonList(hm);  
    18.             }  
    19.             catch (NoSuchBeanDefinitionException ex) {  
    20.                 // Ignore, we'll add a default HandlerMapping later.  
    21.             }  
    22.         }  
    23.   
    24.         // Ensure we have at least one HandlerMapping, by registering  
    25.         // a default HandlerMapping if no other mappings are found.  
    26.         if (this.handlerMappings == null) {  
    27.             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
    28.             if (logger.isDebugEnabled()) {  
    29.                 logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");  
    30.             }  
    31.         }  
    32.     }  


    detectAllHandlerMappings是DispatcherServlet的一个属性,你是可以在web.xml中配置的,默认是true,如果为true,则会去从本工程mvc-servlet.xml文件中去探测所有实现了HandlerMapping的bean,如果有,则加入DispatcherServlet的handlerMappings中。如果detectAllHandlerMappings为false,则直接去容器中找id="handlerMapping"且实现了HandlerMapping的bean.如果以上都没找到,则会去加载默认的HandlerMapping。 

    Java代码  收藏代码
    1. /** Detect all HandlerMappings or just expect "handlerMapping" bean? */  
    2.     private boolean detectAllHandlerMappings = true;  


    本工程由于没有配置HandlerMapping,所以它会去加载默认的,下面看看默认的配置是什么 

    Java代码  收藏代码
    1. protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {  
    2.         String key = strategyInterface.getName();  
    3. //defaultStrategies存储了默认的配置  
    4.         String value = defaultStrategies.getProperty(key);  
    5.         if (value != null) {  
    6.             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);  
    7.             List<T> strategies = new ArrayList<T>(classNames.length);  
    8.             for (String className : classNames) {  
    9.                 try {  
    10.                     Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());  
    11.                     Object strategy = createDefaultStrategy(context, clazz);  
    12.                     strategies.add((T) strategy);  
    13.                 }  
    14.                 catch (ClassNotFoundException ex) {  
    15.                     throw new BeanInitializationException(  
    16.                             "Could not find DispatcherServlet's default strategy class [" + className +  
    17.                                     "] for interface [" + key + "]", ex);  
    18.                 }  
    19.                 catch (LinkageError err) {  
    20.                     throw new BeanInitializationException(  
    21.                             "Error loading DispatcherServlet's default strategy class [" + className +  
    22.                                     "] for interface [" + key + "]: problem with class file or dependent class", err);  
    23.                 }  
    24.             }  
    25.             return strategies;  
    26.         }  
    27.         else {  
    28.             return new LinkedList<T>();  
    29.         }  
    30.     }  


    继续看看defaultStrategies是如何初始化的: 

    Java代码  收藏代码
    1. private static final Properties defaultStrategies;  
    2.   
    3.     static {  
    4.         // Load default strategy implementations from properties file.  
    5.         // This is currently strictly internal and not meant to be customized  
    6.         // by application developers.  
    7.         try {  
    8. //这里的DEFAULT_STRATEGIES_PATH就是DispatcherServlet.properties  
    9.             ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);  
    10.             defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);  
    11.         }  
    12.         catch (IOException ex) {  
    13.             throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());  
    14.         }  
    15.     }  


    这里使用静态代码块来加载配置文件DispatcherServlet.properties,它所在位置就是和DispatcherServlet同一目录下面的,如下图所示: 


    该默认的配置文件的内容如下: 

    Java代码  收藏代码
    1. # Default implementation classes for DispatcherServlet's strategy interfaces.  
    2. # Used as fallback when no matching beans are found in the DispatcherServlet context.  
    3. # Not meant to be customized by application developers.  
    4.   
    5. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver  
    6.   
    7. org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver  
    8.   
    9. #这里就是默认的HandlerMapping的配置  
    10. org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,  
    11.     org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping  
    12. #这里就是默认的HandlerAdapter的配置  
    13. org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,  
    14.     org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,  
    15.     org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter  
    16.   
    17. org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,  
    18.     org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,  
    19.     org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver  
    20.   
    21. org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator  
    22.   
    23. org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver  
    24.   
    25. org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager  


    也就是说,当你什么都没有配置时,默认会加载以上的配置。正是由于有了上述默认配置的BeanNameUrlHandlerMapping(它要求name必须是以/开头的),它才会存储我们在mvc-servlet.xml中配置的<bean name="/index" class="com.lg.mvc.HomeAction"></bean>,同样正是由于有了SimpleControllerHandlerAdapter(由于handler实现了Controller接口,所以它的support方法支持我们的handler),才会调度执行HomeAction的handleRequest方法。

  • 相关阅读:
    大佬讲话听后感
    P1226快速幂取余
    对拍
    P1017 进制转换
    P1092 虫食算 NOIP2002
    P1003 铺地毯
    P1443 马的遍历
    P1032 字串变换
    P1379 八数码问题
    2-MAVEN 基本命令
  • 原文地址:https://www.cnblogs.com/dreamworlds/p/5396209.html
Copyright © 2011-2022 走看看