Springmvc中对 @RequestMapping 注解的处理

236 阅读2分钟

SpringMvc中对 @RequestMapping注解的处理流程可以分为下面6步:

1.注册RequestMappingHandlerMapping bean

在AnnotationDrivenBeanDefinitionParser类的parse()方法中:

@Override
public BeanDefinition parse(Element element, ParserContext context) {
    Object source = context.extractSource(element);
    XmlReaderContext readerContext = context.getReaderContext();
    //生成RequestMappingHandlerMapping bean信息
    RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
    handlerMappingDef.setSource(source);
    handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    handlerMappingDef.getPropertyValues().add("order", 0);
    handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
    //此处HANDLER_MAPPING_BEAN_NAME值为:RequestMappingHandlerMapping类名
    //容器中注册name为RequestMappingHandlerMapping类名
    context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
}

可以看到上面方法在Spring MVC容器中注册了一个名为“HANDLER_MAPPING_BEAN_NAME”的bean。

2.实例化RequestMappingHandlerMapping bean。

进入initHandlerMethods初始化方法查看逻辑:

protected void initHandlerMethods() {
    //1.获取容器中所有bean 的name。
    //根据detectHandlerMethodsInAncestorContexts bool变量的值判断是否获取父容器中的bean,默认为false。因此这里只获取Spring MVC容器中的bean,不去查找父容器
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
         BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
         getApplicationContext().getBeanNamesForType(Object.class));
    //循环遍历bean
    for (String beanName : beanNames) {
	//2.判断bean是否含有@Controller或者@RequestMappin注解
        if (beanType != null && isHandler(beanType)) {
            //3.对含有注解的bean进行处理,获取handler函数信息。
              detectHandlerMethods(beanName);
      }
}
@Override
protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

(1)获取Spring MVC容器中的bean。 (2)找出含有含有@Controller或者@RequestMappin注解的bean。 (3)对含有注解的bean进行解析。

查看detectHandlerMethods()方法。

protected void detectHandlerMethods(final Object handler) {
    //1.获取bean的类信息
    Class<?> handlerType = (handler instanceof String ?
         getApplicationContext().getType((String) handler) : handler.getClass());
    final Class<?> userType = ClassUtils.getUserClass(handlerType);
    //2.遍历函数获取有@RequestMapping注解的函数信息
   Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
         new MethodIntrospector.MetadataLookup<T>() {
            @Override
            public T inspect(Method method) {
               try {
                //如果有@RequestMapping注解,则获取函数映射信息
                return getMappingForMethod(method, userType);
               }
         });
    //3.遍历映射函数列表,注册handler
    for (Map.Entry<Method, T> entry : methods.entrySet()) {
      Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
      T mapping = entry.getValue();
      //注册handler函数
      registerHandlerMethod(handler, invocableMethod, mapping);
   }
}
看看createRequestMappingInfo是如何实现的。
protected RequestMappingInfo createRequestMappingInfo(
      RequestMapping requestMapping, RequestCondition<?> customCondition) {
         return RequestMappingInfo
         .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
         .methods(requestMapping.method())
         .params(requestMapping.params())
         .headers(requestMapping.headers())
         .consumes(requestMapping.consumes())
         .produces(requestMapping.produces())
         .mappingName(requestMapping.name())
         .customCondition(customCondition)
         .options(this.config)
         .build();
}

可以看到上面把RequestMapping注解中的信息都放到一个RequestMappingInfo实例中后返回。 当生成含有@RequestMapping注解的函数映射信息后,最后一步是调用registerHandlerMethod 注册handler和处理函数映射关系。

3.获取RequestMappingHandlerMapping bean实例。

initHandlerMappings方法中:

private void initHandlerMappings(ApplicationContext context) {
    //容器中查找name为"ANDLER_MAPPING_BEAN_NAME"的实例
    HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
    //把找到的bean放到hanlderMappings中。
    this.handlerMappings = Collections.singletonList(hm);
}

进入initHandlerMappings()方法。 此处我们看到从容器中获取了name为 “HANDLER_MAPPING_BEAN_NAME”的bean,这个bean大家应该还记得吧,就是前面注册并实例化了的HandlerMapping bean。

4.接收requst请求。

5.在RequestMappingHandlerMapping实例中查找对应的handler。

6.handler处理请求。