SpringMVC源码 HandlerMapping和HandlerAdapter(3)

来源:互联网 发布:网络迷宫 mkv 编辑:程序博客网 时间:2024/05/02 02:17

上一节主要阅读了BeanNameUrlHandlerMapping类,并理清了它的父类关系,值得注意的是它的爷爷的爸爸也就是AbstractHandlerMapping实现了HandlerMapping接口,而继承了WebApplicationObjectSupport类,在AbstractDetectingUrlHandlerMapping类中,有这样一个方法:

Java代码  收藏代码
  1. /** 
  2.      * Calls the {@link #detectHandlers()} method in addition to the 
  3.      * superclass's initialization. 
  4.      */  
  5.     @Override  
  6.     public void initApplicationContext() throws ApplicationContextException {  
  7.         super.initApplicationContext();  
  8.         detectHandlers();  
  9.     }  

 上一节没有说明这个,经过我翻WebApplicationObjectSupport类和它的父类ApplicationObjectSupport发现有一个setApplicationContext(ApplicationContext context)方法,在其中调用了initApplicationContext方法,前面的setter肯定是在bean构造时用到的,更上层的以后再去阅读理解吧,到这里就追溯到了handler探测的本源。

 DefaultAnnoationHandlerMapping类也是继承自AbstractDetectingUrlHandlerMapping类,则必然实现了它的抽象方法:

Java代码  收藏代码
  1. /** 
  2.      * Determine the URLs for the given handler bean. 
  3.      * @param beanName the name of the candidate bean 
  4.      * @return the URLs determined for the bean, 
  5.      * or <code>null</code> or an empty array if none 
  6.      */  
  7.     protected abstract String[] determineUrlsForHandler(String beanName);  

  那么detectHandler接下来的执行顺序就和上一节的顺序相同,这时我们跳到了DefaultAnnoationHandlerMapping类中的该方法:

Java代码  收藏代码
  1. /** 
  2.      * Checks for presence of the {@link org.springframework.web.bind.annotation.RequestMapping} 
  3.      * annotation on the handler class and on any of its methods. 
  4.      */  
  5.     @Override  
  6.     protected String[] determineUrlsForHandler(String beanName) {  
  7.         ApplicationContext context = getApplicationContext();  
  8.         Class<?> handlerType = context.getType(beanName);  
  9.         RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class);  
  10.         if (mapping != null) {  
  11.             // @RequestMapping found at type level  
  12.             this.cachedMappings.put(handlerType, mapping);  
  13.             Set<String> urls = new LinkedHashSet<String>();  
  14.             String[] typeLevelPatterns = mapping.value();  
  15.             if (typeLevelPatterns.length > 0) {  
  16.                 // @RequestMapping specifies paths at type level  
  17.                 String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType);  
  18.                 for (String typeLevelPattern : typeLevelPatterns) {  
  19.                     if (!typeLevelPattern.startsWith("/")) {  
  20.                         typeLevelPattern = "/" + typeLevelPattern;  
  21.                     }  
  22.                     for (String methodLevelPattern : methodLevelPatterns) {  
  23.                         String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern);  
  24.                         addUrlsForPath(urls, combinedPattern);  
  25.                     }  
  26.                     addUrlsForPath(urls, typeLevelPattern);  
  27.                 }  
  28.                 return StringUtils.toStringArray(urls);  
  29.             }  
  30.             else {  
  31.                 // actual paths specified by @RequestMapping at method level  
  32.                 return determineUrlsForHandlerMethods(handlerType);  
  33.             }  
  34.         }  
  35.         else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {  
  36.             // @RequestMapping to be introspected at method level  
  37.             return determineUrlsForHandlerMethods(handlerType);  
  38.         }  
  39.         else {  
  40.             return null;  
  41.         }  
  42.     }  

 既然是默认注解支持的HandlerMapping,那么它必然是去探测@RequestMapping所注解的Handler和Method。这里就有必要来看看RequestMapping接口的定义:

Java代码  收藏代码
  1. @Target({ElementType.METHOD, ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. @Mapping  
  5. public @interface RequestMapping {  
  6.   
  7.     String[] value() default {};  
  8.   
  9.     RequestMethod[] method() default {};  
  10.   
  11.     String[] params() default {};  
  12.   
  13.     String[] headers() default {};   
  14.   
  15. }  

 value数组显然是存储所有该Handler中的url,method则是POST GET等方法,RequestMethod是一个enum类型

Java代码  收藏代码
  1. public enum RequestMethod {  
  2.   
  3.     GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE  
  4.   
  5. }  

 context.findAnnotationOnBean(beanName, RequestMapping.class)显然是查找了该Handler上所有使用了@RequestMapping的注解,将它们的value,method取出,再封装到RequestMapping类对象中。接下来的加入缓存语句就不用解释了。

我们来看看determineUrlsForHandlerMethods方法的源码:

Java代码  收藏代码
  1. /** 
  2.      * Derive URL mappings from the handler's method-level mappings. 
  3.      * @param handlerType the handler type to introspect 
  4.      * @return the array of mapped URLs 
  5.      */  
  6.     protected String[] determineUrlsForHandlerMethods(Class<?> handlerType) {  
  7.         final Set<String> urls = new LinkedHashSet<String>();  
  8.         Class<?>[] handlerTypes =  
  9.                 Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class<?>[]{handlerType};  
  10.         for (Class<?> currentHandlerType : handlerTypes) {  
  11.             ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {  
  12.                 public void doWith(Method method) {  
  13.                     RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);  
  14.                     if (mapping != null) {  
  15.                         String[] mappedPaths = mapping.value();  
  16.                         for (String mappedPath : mappedPaths) {  
  17.                             addUrlsForPath(urls, mappedPath);  
  18.                         }  
  19.                     }  
  20.                 }  
  21.             });  
  22.         }  
  23.         return StringUtils.toStringArray(urls);  
  24.     }  

 这里就比较麻烦了,先从字面意思理解就是查询类中的方法,找到方法对应的RequestMapping的所包含的value,组成一个url数组。

接下来看它的实现,首先是检查了handlerType是否是一个代理类

Java代码  收藏代码
  1. /** 
  2.      * Returns true if and only if the specified class was dynamically 
  3.      * generated to be a proxy class. 
  4. */  
  5. public static boolean isProxyClass(Class<?> cl) {  
  6.     if (cl == null) {  
  7.         throw new NullPointerException();  
  8.     }  
  9.          
  10.     return proxyClasses.containsKey(cl);  
  11.     }  
  12.   
  13. /** set of all generated proxy classes, for isProxyClass implementation */  
  14.     private static Map proxyClasses =  
  15.     Collections.synchronizedMap(new WeakHashMap());  

 接下来是反射和回调,我也看到云里雾里的。。。。理解不来,以后再想吧,直到它最后是得到的url就行了。

handlerType.getInterfaces();

用于得到所有handlerType实现的接口的Class对象

new Class<?>[]{handlerType}

得到的还只是handlerType的Class对象

0 0
原创粉丝点击