SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

Spring 源码解析——SpringMVC 源码解析(初探 HandlerMapping、HandlerExecutionChain 和 HandlerAdapter)(三) 目录 一、概述 二、功能介绍和部分源码解析 2.1 HandlerMapping 2.2 HandlerExecutionChain 2.3 HandlerAdapter 三、内容总结 写文章不易,转载请标明出处。 同时,如果你喜欢我的文章,请关注我,让我们一起进步。 一、概述 通过上一篇博文中对SpringMVC 处理请求流程的源码分析,已经对 SpringMVC 中... 阅读详情

http://www.cnblogs.com/dreamworlds/p/5396209.html


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

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

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

  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文件的内容: 

  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。内容为: 

  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,内容为: 

  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方法中。 

  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.     }  


第一步详细查看: 

  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本身的一些拦截器,如下 

  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实现: 

  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这只用实现该方法中的一部分),如下 

  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());的具体实现: 

  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)方法: 

  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也是这样类似的逻辑 

  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初始化的时候,会调用一个方法如下: 

  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,这两个方法非常重要,理解了这两个方法你就会知道,配置不对问题出在哪里,下面具体看下这两个方法: 

  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。 

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


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

  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是如何初始化的: 

  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同一目录下面的,如下图所示: 


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

  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方法。


SpringMVC中的Handler、HandlerMapping、HandlerAdapter 目前,我们知道了HandlerMapping是用于将请求映射到一个HandlerExecutionChain的,而HandlerExecutionChain主要执行该请求的所有Interceptor,用于对请求进行拦截和善后,并且它保存了实际的Handler对象,该对象是Object类型,不和任何框架中的处理器类耦合,这给了其它框架整合到SpringMVC的能力。讲实话,要不是这学期扫一眼学校的课件,我都不知道有这东西,这东西本来就是对使用框架进行开发的开发者隐藏的。不知道也没关系,现在你知道它的作用了。 阅读详情

相关推荐

手把手教你用Matlab/Simulink搭建PMSM的SMO无感FOC仿真(附相位补偿与离散化代码)

本文详细介绍了基于滑模观测器(SMO)的永磁同步电机(PMSM)无传感器FOC控制方法,通过Matlab/Simulink平台实现从理论到实践的完整流程。内容涵盖SMO核心原理、离散化处理、转子位置估算与相位补偿技术,以及双闭环控制系统搭建,为工程师提供了一套完整的无传感器控制解决方案。

weixin_27038245的博客 252

springMVC HandlerMapping组件介绍

1:简单介绍 该组件作用是根据请求信息获取对应的处理请求的handler,职责很单一,只干这一件事。该组件对应的接口是org.springframework.web.servlet.HandlerMapping,只有唯一的一个用来根据请求获取handler的方法getHandler(req),源码如下: public interface HandlerMapping { String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getNam

wang0907的博客 1701

Visio 2013 Professional密钥安装激活全攻略:版本匹配与故障排查

产品密钥是软件授权体系中的核心凭证,用于验证用户对软件的使用权限。在微软Office产品线中,Visio 2013 Professional采用25位字符的密钥机制,通过联网或电话方式完成激活。正确使用密钥不仅能确保软件功能完整,还能避免因授权问题导致的工作中断。对于企业IT运维和个人用户而言,掌握密钥类型辨析、安装包匹配规则以及激活失败排查方法,是保障老版本软件稳定运行的关键。本文围绕Visio 2013 Professional,详细讲解密钥输入、激活流程及常见错误代码处理,帮助读者高效完成部署与维护。

weixin_28487433的博客 328

Caused by: org.jbpm.api.JbpmException: resource jbpm.cfg.xml does not exist

1、错误描述2015-09-20 22:49:59 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt org.springframew

游海东的技术专栏 3822

UE5新手必看:如何用蓝图系统快速打造赛车游戏(含Chaos Physics配置)

本文为UE5新手提供使用蓝图系统快速打造赛车游戏的完整指南,涵盖Chaos Physics配置、载具蓝图架构设计、控制逻辑实现等关键步骤。通过详细的实战案例和优化技巧,帮助开发者高效构建具备专业物理反馈的赛车游戏原型。

weixin_29001327的博客 387

22、自动化地图制作与Pandas数据处理

本文介绍了在ArcGIS Pro中使用arcpy.mp模块进行自动化地图制作的关键技术,涵盖地图元素的访问、移动与文本修改,以及将布局批量导出为JPEG、PNG和PDF格式的方法。同时,文章深入探讨了Pandas在数据处理和地理空间分析中的应用,特别是Spatially Enabled DataFrames(SEDFs)的使用。通过综合案例展示了地图更新与数据清洗、分析的结合,提升了地图制作与数据处理的效率,为GIS自动化工作流提供了实用指南。

w8x9y0z1的博客 78

Spring MVC 三种常见的HandlerMapping

根据前面的知识,我们知道路由映射器是用于检查请求是否能够被处理,需要哪些步骤进行处理的“路由表”。 1.SimpleUrlHandlerMapping(不推荐) 需要对url和处理器进行一一匹配 <bean id="helloController" class="com.learn.controllers.HelloController"/> <!-- 配置映射器 --> <bean class="org.springframework.web.servlet..

『程序员·小李』的博客 778

如何调用 DBMS_DISKGROUP 对 ASM 文件进行随机读取

该篇博客介绍了如何通过 Java 调用 DBMS_DISKGROUP 读写 Oracle ASM 共享存储文件,并提供了 Java Demo。并测试出 DBMS_DISKGROUP 存在性能瓶颈。

我要出家当道士 1178

handleradapter原理_SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

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

weixin_35568959的博客 317

10|Git Diff 与增量代码识别:本次到底改了哪些代码?

本文介绍 Git Diff 和增量代码识别,帮助你理解精准测试如何先找到本次真正变化的代码。测试开发工程师。Java 后端开发工程师。质量平台 / DevOps 平台建设者。想了解精准测试落地方法的技术负责人。

专注 AI 精准测试平台实战落地,分享从代码 Diff 到回归决策的完整工程闭环。主张“先建数据链路,再上 AI 智能”,让测试从“靠经验”走向“基于风险”。 160

GEE土地分类:土地分类精度评定和分类后影像进行(Kmeans,Gmeans,SNIC (Simple Non-Iterative Clustering)聚类分析和滤波(focal_mode)分析

使用聚类分析和滤波分析来进一步处理土地分类后的影像数据。聚类分析可以帮助您识别影像中的相似区域。您可以使用聚类算法,如K均值聚类或层次聚类,将像素分组到具有相似像素值的群集中。这可以帮助您更好地理解图像中的空间模式和结构,并可能揭示有用的信息。滤波分析可以帮助您平滑图像并去除噪声。常见的滤波器包括中值滤波器和高斯滤波器。这些滤波器可以帮助您消除图像中的随机变化,并使其更易于解释和分析。

此星光明博客 2516

【推荐】SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

来源:http://www.360doc.com/content/14/1024/23/18637323_419613178.shtml 刚接触SpringMVC,对它的xml文件配置一直比较模模糊糊,最近花了一点时间稍微看了下源代码,再加上调试,开始逐渐理解它,网上的

aosica321的专栏 1098

【车联网】Automotive 软件过程能力成熟度模型——ASPICE标准入门介绍

ASPICE标准详细定义了与汽车电子软件开发相关的各种术语和概念,包括软件组件、系统集成、测试和验证等。这些定义确保了所有开发团队在使用相同术语时具有一致的理解。

奶爸的编程之路,也就一周冷个三天 2677

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

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

a23796928的博客 140

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

SpringMVC中HandlerMapping和HandlerAdapter详解(适配器模式)

SpringMVC中HandlerMapping和HandlerAdapter详解(设配器模式)

scorpio的博客 1万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

SpringMVC中的HandlerMapping和HandlerAdapter

文章目录1、HandlerMapping1.1、 AbstractUrlHandlerMapping1.1.1、AbstractUrlHandlerMapping 实现类及使用1.1.2 、Controller 类1.2、AbstractHandlerMethodMapping1.3、AbstractHandlerMapping 实现类及使用2、HandlerAdapter2.1、RequestMappingHandlerAdapter2.2、HttpRequestHandlerAdapter2.

qgnczmnmn的博客 632

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: Netty系列之Netty编解码框架分析
下一篇: maven 不能加载ojdbc14.jar解决方法
小瑞
博客等级 码龄19年 240粉丝 274原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值