欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringMVC源码总结(二)mvc:annotation 博客分类: Spring框架  

程序员文章站 2024-03-24 19:41:58
...

SpringMVC源码总结(二)mvc:annotation

     
 

 

 

 

   

 

 
 
上一篇文章让我们了解HandlerMapping和HandlerAdapter以及默认采取的策略,这篇文章就要讲述mvc:annotation-driven对默认策略的改变。它背后到底注册了哪些HandlerMapping和HandlerAdapter。 

首先可以在DispatcherServlet的initStrategies方法中的initHandlerMappings和initHandlerAdapters中打上断点,来查看注册了哪些HandlerMapping和HandlerAdapter
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. protected void initStrategies(ApplicationContext context) {  

  2.         initMultipartResolver(context);  

  3.         initLocaleResolver(context);  

  4.         initThemeResolver(context);  

  5.         initHandlerMappings(context);  

  6.         initHandlerAdapters(context);  

  7.         initHandlerExceptionResolvers(context);  

  8.         initRequestToViewNameTranslator(context);  

  9.         initViewResolvers(context);  

  10.         initFlashMapManager(context);  

  11.     }  


目前我的spring版本是4.0.5。我查看的结果: 
HandlerMapping:注册了 RequestMappingHandlerMapping和BeanNameUrlHandlerMapping 
HandlerAdapter:注册了 RequestMappingHandlerAdapter、HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter 
这几个HandlerMapping和HandlerAdapter上文都提到过。 
下面就要查看下具体的注册过程: 
在xml文件中配置mvc:annotation-driven,肯定有一个专门的类来解析处理这个东西。 
会有这样的一个接口BeanDefinitionParser,它只有一个方法:
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. public interface BeanDefinitionParser {  

  2.   

  3.     /** 

  4.      * Parse the specified {@link Element} and register the resulting 

  5.      * {@link BeanDefinition BeanDefinition(s)} with the 

  6.      * {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry} 

  7.      * embedded in the supplied {@link ParserContext}. 

  8.      * <p>Implementations must return the primary {@link BeanDefinition} that results 

  9.      * from the parse if they will ever be used in a nested fashion (for example as 

  10.      * an inner tag in a {@code <property/>} tag). Implementations may return 

  11.      * {@code null} if they will <strong>not</strong> be used in a nested fashion. 

  12.      * @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions} 

  13.      * @param parserContext the object encapsulating the current state of the parsing process; 

  14.      * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} 

  15.      * @return the primary {@link BeanDefinition} 

  16.      */  

  17.     BeanDefinition parse(Element element, ParserContext parserContext);  

  18.   

  19. }  


它是用来专门处理<beans></beans>里面的配置元素。然后我们会找到这样的一个实现类AnnotationDrivenBeanDefinitionParser,它的文档介绍如下: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.  * 这里清清楚楚写着该类是专门处理 <mvc:annotation-driven/>标签的 

  3.  * A {@link BeanDefinitionParser} that provides the configuration for the 

  4.  * {@code <annotation-driven/>} MVC namespace  element. 

  5.  * 

  6.  * 这里说明了注册的HandlerMapping 

  7.  * <p>This class registers the following {@link HandlerMapping}s:</p> 

  8.  * <ul> 

  9.  *  <li>{@link RequestMappingHandlerMapping} 

  10.  *  ordered at 0 for mapping requests to annotated controller methods. 

  11.  *  <li>{@link BeanNameUrlHandlerMapping} 

  12.  *  ordered at 2 to map URL paths to controller bean names. 

  13.  * </ul> 

  14.  * 

  15.  * <p><strong>Note:</strong> Additional HandlerMappings may be registered 

  16.  * as a result of using the {@code <view-controller>} or the 

  17.  * {@code <resources>} MVC namespace elements. 

  18.  * 

  19.  * 这里说明了注册的HandlerAdapter 

  20.  * <p>This class registers the following {@link HandlerAdapter}s: 

  21.  * <ul> 

  22.  *  <li>{@link RequestMappingHandlerAdapter} 

  23.  *  for processing requests with annotated controller methods. 

  24.  *  <li>{@link HttpRequestHandlerAdapter} 

  25.  *  for processing requests with {@link HttpRequestHandler}s. 

  26.  *  <li>{@link SimpleControllerHandlerAdapter} 

  27.  *  for processing requests with interface-based {@link Controller}s. 

  28.  * </ul> 

  29.  * 

  30.  * <p>This class registers the following {@link HandlerExceptionResolver}s: 

  31.  * <ul> 

  32.  *  <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions 

  33.  *  through @{@link ExceptionHandler} methods. 

  34.  *  <li>{@link ResponseStatusExceptionResolver} for exceptions annotated 

  35.  *  with @{@link ResponseStatus}. 

  36.  *  <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring 

  37.  *  exception types 

  38.  * </ul> 

  39.  * 

  40.  * <p>Both the {@link RequestMappingHandlerAdapter} and the 

  41.  * {@link ExceptionHandlerExceptionResolver} are configured with instances of 

  42.  * the following by default: 

  43.  * <ul> 

  44.  *  <li>A {@link ContentNegotiationManager} 

  45.  *  <li>A {@link DefaultFormattingConversionService} 

  46.  *  <li>A {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} 

  47.  *  if a JSR-303 implementation is available on the classpath 

  48.  *  <li>A range of {@link HttpMessageConverter}s depending on what 3rd party 

  49.  *  libraries are available on the classpath. 

  50.  * </ul> 

  51.  * 

  52.  * @author Keith Donald 

  53.  * @author Juergen Hoeller 

  54.  * @author Arjen Poutsma 

  55.  * @author Rossen Stoyanchev 

  56.  * @author Brian Clozel 

  57.  * @since 3.0 

  58.  */  

  59. class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {  

  60.           //先省略,请详细看下它的文档介绍  

  61. }  


上面的文档对mvc:annotation-driven注册的东西都有详细的说明。 
具体看解析过程的代码的内容:
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. @Override  

  2.     public BeanDefinition parse(Element element, ParserContext parserContext) {  

  3.         Object source = parserContext.extractSource(element);  

  4.   

  5.         //省略  

  6.         RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);  

  7.           

  8.         RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);  

  9.           

  10.             //省略,  

  11.         // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"  

  12.         MvcNamespaceUtils.registerDefaultComponents(parserContext, source);  

  13.   

  14.         parserContext.popAndRegisterContainingComponent();  

  15.   

  16.         return null;  

  17.     }  


MvcNamespaceUtils.registerDefaultComponents的内容如下: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. public static void registerDefaultComponents(ParserContext parserContext, Object source) {  

  2.         registerBeanNameUrlHandlerMapping(parserContext, source);  

  3.         registerHttpRequestHandlerAdapter(parserContext, source);  

  4.         registerSimpleControllerHandlerAdapter(parserContext, source);  

  5.     }  


至此所注册的HandlerMapping和HandlerAdapter我们都找到了。 
然后我们就可以体验下RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,这两个HandlerMapping。由于上一篇文章已经体验过了BeanNameUrlHandlerMapping,接下来就要体验下RequestMappingHandlerMapping,然后你会发觉又有一系列的新名词走进我们的视野,需要我们去弄清楚。 
先体验下: 

首先还是web.xml的配置:
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  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>  


最简单的配置,然后是[servlet-name]-servlet.xml,本工程即mvc-servlet.xml: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  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.       

  13.     <mvc:annotation-driven/>  

  14.       

  15.     <bean class="com.lg.mvc.StringAction"/>  

  16.     <bean name="/index" class="com.lg.mvc.HomeAction"></bean>  

  17.       

  18.       

  19.     <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  

  20.         <property name="templateLoaderPath" value="/WEB-INF/views" />  

  21.         <property name="defaultEncoding" value="utf-8" />  

  22.         <property name="freemarkerSettings">  

  23.             <props>  

  24.                 <prop key="locale">zh_CN</prop>  

  25.             </props>  

  26.         </property>  

  27.     </bean>  

  28.     <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  

  29.         <property name="suffix" value=".html" />  

  30.         <property name="contentType" value="text/html;charset=utf-8" />  

  31.         <property name="requestContextAttribute" value="request" />  

  32.         <property name="exposeRequestAttributes" value="true" />  

  33.         <property name="exposeSessionAttributes" value="true" />  

  34.     </bean>  

  35. </beans>  


开启了<mvc:annotation-driven/>,同时注册了两个bean。有RequestMappingHandlerMapping和RequestMappingHandlerAdapter作为后盾支持,然后我们就可以在bean中使用@Controller和@RequestMapping两个标签了。@Controller本身其实与@RequestMapping无关的,它只是@Component中的一个重要的标签而已,但是我们会在源码里看到它对RequestMappingHandlerMapping也是挺重要的,但不是必须的。这里简单说明下:RequestMappingHandlerMapping它会判断一个bean是否含有@Controller标签或者@RequestMapping,如果有其一则会将该bean纳入作为它的处理对象,之后会进一步处理该类上含有@RequestMapping注解的方法。这样做主要是由于@RequestMapping可以配置在类上(作为基础地址),也可以配置在方法上,我们有时候会在类上配置@RequestMapping,有时候又不会,所以只要类含有@Controller或者含有@RequestMapping,RequestMappingHandlerMapping都会将他们纳入自己的handler管辖范围。所以仅仅在方法中含有@RequestMapping注解是不被处理的,必须在类上加入@RequestMapping或者@Controller,而@Controller又不是必须的,你可以试验下,稍后会做源代码说明。下面继续,列出使用了@Controller和@RequestMapping注解的StringAction类 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. package com.lg.mvc;  

  2.   

  3. import java.io.UnsupportedEncodingException;  

  4.   

  5. import org.springframework.stereotype.Controller;  

  6. import org.springframework.web.bind.annotation.RequestMapping;  

  7. import org.springframework.web.bind.annotation.RequestMethod;  

  8. import org.springframework.web.bind.annotation.ResponseBody;  

  9.   

  10. @Controller  

  11. public class StringAction {  

  12.       

  13.     @ResponseBody  

  14.     @RequestMapping(value="/string",method=RequestMethod.GET)  

  15.     public String testMessageConverter(String name) throws UnsupportedEncodingException{  

  16.         System.out.println(name);  

  17.         return name;  

  18.     }  

  19. }  


然后就可以运行一下,体验一下,先不要管乱码问题,这个问题引出了下一篇文章spring框架中的乱码问题。 
运行结果如下: 

SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架   
证明整个流程跑通了。 
首先@Controller使得StringAction这个handler纳入RequestMappingHandlerMapping管理,RequestMappingHandlerMapping会将这个handler和handler中的每一个含有@RequestMapping的方法都会构建成一个HandlerMethod对象,该类的构造函数为HandlerMethod(Object bean, Method method),经过这样的包装之后将构造的HandlerMethod对象作为新的handler,然后进行选择适配器,进行方法调用,当RequestMappingHandlerAdapter判断是否support一个类时,就是依据当前的handlelr是否是HandlerMethod类型。若是则由RequestMappingHandlerAdapter来调度执行该handler(handler为HandlerMethod类型)的中的method方法。以上就是整个大体的流程。下面就要用代码来事实说话: 
第一步要弄清RequestMappingHandlerMapping在初始化时是如何寻找它所管辖的bean。说说我找代码的具体流程: 
RequestMappingHandlerMapping的父类AbstractHandlerMethodMapping在初始化时,会调用到这样的一个方法initHandlerMethods,在该方法中,遍历所有的bean然后判断他们是不是含有@Controller或者@RequestMapping注解:
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Scan beans in the ApplicationContext, detect and register handler methods. 

  3.      * @see #isHandler(Class) 

  4.      * @see #getMappingForMethod(Method, Class) 

  5.      * @see #handlerMethodsInitialized(Map) 

  6.      */  

  7.     protected void initHandlerMethods() {  

  8.         if (logger.isDebugEnabled()) {  

  9.             logger.debug("Looking for request mappings in application context: " + getApplicationContext());  

  10.         }  

  11.   

  12.         String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?  

  13.                 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :  

  14.                 getApplicationContext().getBeanNamesForType(Object.class));  

  15.   

  16.         for (String beanName : beanNames) {  

  17.             if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&  

  18.                     isHandler(getApplicationContext().getType(beanName))){  

  19.                 detectHandlerMethods(beanName);  

  20.             }  

  21.         }  

  22.         handlerMethodsInitialized(getHandlerMethods());  

  23.     }  


其中的isHandler的判断方法代码如下: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * {@inheritDoc} 

  3.      * Expects a handler to have a type-level @{@link Controller} annotation. 

  4.      */  

  5.     @Override  

  6.     protected boolean isHandler(Class<?> beanType) {  

  7.         return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||  

  8.                 (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));  

  9.     }  


如果handler含有了上述注解的其中之一,就会进一步处理该handler的方法中含有@RequestMapping的方法: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Look for handler methods in a handler. 

  3.      * @param handler the bean name of a handler or a handler instance 

  4.      */  

  5.     protected void detectHandlerMethods(final Object handler) {  

  6.         Class<?> handlerType =  

  7.                 (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());  

  8.   

  9.         // Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances  

  10.         final Map<Method, T> mappings = new IdentityHashMap<Method, T>();  

  11.         final Class<?> userType = ClassUtils.getUserClass(handlerType);  

  12.   

  13.         Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {  

  14.             @Override  

  15.             public boolean matches(Method method) {  

  16.                 T mapping = getMappingForMethod(method, userType);  

  17.                 if (mapping != null) {  

  18.                     mappings.put(method, mapping);  

  19.                     return true;  

  20.                 }  

  21.                 else {  

  22.                     return false;  

  23.                 }  

  24.             }  

  25.         });  

  26.   

  27.         for (Method method : methods) {  

  28.             registerHandlerMethod(handler, method, mappings.get(method));  

  29.         }  

  30.     }  


遍历这个handler类的所有方法,过滤条件就是这个内部类MethodFilter,其中的getMappingForMethod方法内容为: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Uses method and type-level @{@link RequestMapping} annotations to create 

  3.      * the RequestMappingInfo. 

  4.      * @return the created RequestMappingInfo, or {@code null} if the method 

  5.      * does not have a {@code @RequestMapping} annotation. 

  6.      * @see #getCustomMethodCondition(Method) 

  7.      * @see #getCustomTypeCondition(Class) 

  8.      */  

  9.     @Override  

  10.     protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {  

  11.         RequestMappingInfo info = null;  

  12.         RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);  

  13.         if (methodAnnotation != null) {  

  14.             RequestCondition<?> methodCondition = getCustomMethodCondition(method);  

  15.             info = createRequestMappingInfo(methodAnnotation, methodCondition);  

  16.             RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);  

  17.             if (typeAnnotation != null) {  

  18.                 RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);  

  19.                 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);  

  20.             }  

  21.         }  

  22.         return info;  

  23.     }  


如找到了含有RequestMapping注释的方法,则由这个注释的内容构建一个RequestMappingInfo对象: 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Created a RequestMappingInfo from a RequestMapping annotation. 

  3.      */  

  4.     protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {  

  5.         String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());  

  6.         return new RequestMappingInfo(  

  7.                 new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),  

  8.                         this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),  

  9.                 new RequestMethodsRequestCondition(annotation.method()),  

  10.                 new ParamsRequestCondition(annotation.params()),  

  11.                 new HeadersRequestCondition(annotation.headers()),  

  12.                 new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),  

  13.                 new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),  

  14.                 customCondition);  

  15.     }  


就是拿RequestMapping注释的内容进一步封装进RequestMappingInfo对象中。对handler的所有方法过滤完成之后,就要遍历这些方法,以一定的方式存储起来。 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Register a handler method and its unique mapping. 

  3.      * @param handler the bean name of the handler or the handler instance 

  4.      * @param method the method to register 

  5.      * @param mapping the mapping conditions associated with the handler method 

  6.      * @throws IllegalStateException if another method was already registered 

  7.      * under the same mapping 

  8.      */  

  9.     protected void registerHandlerMethod(Object handler, Method method, T mapping) {  

  10.         HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);  

  11.         HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);  

  12.         if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {  

  13.             throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +  

  14.                     "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +  

  15.                     oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");  

  16.         }  

  17.   

  18.         this.handlerMethods.put(mapping, newHandlerMethod);  

  19.         if (logger.isInfoEnabled()) {  

  20.             logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);  

  21.         }  

  22.   

  23.         Set<String> patterns = getMappingPathPatterns(mapping);  

  24.         for (String pattern : patterns) {  

  25.             if (!getPathMatcher().isPattern(pattern)) {  

  26.                 this.urlMap.add(pattern, mapping);  

  27.             }  

  28.         }  

  29.     }  


这里的this.handlerMethods就包含了所有管辖的bean,key为RequestMappingInfo对象,value为handler和它中含有@RequestMapping注释的方法method构建的HandlerMethod。 
如下所示:
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. /** 

  2.      * Create the HandlerMethod instance. 

  3.      * @param handler either a bean name or an actual handler instance 

  4.      * @param method the target method 

  5.      * @return the created HandlerMethod 

  6.      */  

  7.     protected HandlerMethod createHandlerMethod(Object handler, Method method) {  

  8.         HandlerMethod handlerMethod;  

  9.         if (handler instanceof String) {  

  10.             String beanName = (String) handler;  

  11.             handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);  

  12.         }  

  13.         else {  

  14.             handlerMethod = new HandlerMethod(handler, method);  

  15.         }  

  16.         return handlerMethod;  

  17.     }  


至此,RequestMappingHandlerMapping的初始化注册工作就完成了。然后就是等待请求,访问 
http://localhost:8080/string?name=aa,RequestMappingHandlerMapping会匹配到由StringAction对象和它的包含注释的方法testMessageConverter构建的HandlerMethod对象,该对象将作为handler,然后再遍历HandlerAdapter判断它们是否支持这个handler,RequestMappingHandlerAdapter的判断依据为是否是HandlerMethod 类型(在AbstractHandlerMethodAdapter类中):
 

Java代码  SpringMVC源码总结(二)mvc:annotation
            
    
    博客分类: Spring框架  

  1. public final boolean supports(Object handler) {  

  2.         return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler);  

  3.     }  

  4.