SpringMVC源码之Controller查找原理

本文深入探讨SpringMVC的Controller查找原理,从源码角度解析请求处理流程、初始化过程,包括RequestMappingInfo和HandlerMethod的角色,以及如何在初始化和运行时检查RequestMapping配置的歧义性。详细阐述了查找HandlerMethod的逻辑,明确了匹配顺序和冲突解决策略。
摘要由CSDN通过智能技术生成

摘要

  • 本文从源码层面简单讲解SpringMVC的处理器映射环节,也就是查找Controller详细过程。

SpringMVC请求流程

  • Controller查找在上图中对应的步骤1至2的过程

SpringMVC初始化过程

理解初始化过程之前,先认识两个类
  1. RequestMappingInfo类,对RequestMapping注解封装。里面包含http请求头的相关信息。如uri、method、params、header等参数。一个对象对应一个RequestMapping注解
  2. HandlerMethod类,是对Controller的处理请求方法的封装。里面包含了该方法所属的bean对象、该方法对应的method对象、该方法的参数等。
  • 上图是RequestMappingHandlerMapping的继承关系。在SpringMVC初始化的时候,首先执行RequestMappingHandlerMapping中的afterPropertiesSet方法,然后会进入AbstractHandlerMethodMapping的afterPropertiesSet方法(line:93),这个方法会进入当前类的initHandlerMethods方法(line:103)。这个方法的职责便是从applicationContext中扫描beans,然后从bean中查找并注册处理器方法,代码如下。
protected void initHandlerMethods() {
  if (logger.isDebugEnabled()) {
      logger.debug("Looking for request mappings in application context: " + getApplicationContext());
  }
  //获取applicationContext中所有的bean name
  String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
        BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
        getApplicationContext().getBeanNamesForType(Object.class));
  //遍历beanName数组
  for (String beanName : beanNames) {
      //isHandler会根据bean来判断bean定义中是否带有Controller注解或RequestMapping注解
      if (isHandler(getApplicationContext().getType(beanName))){
        detectHandlerMethods(beanName);
      }
  }
  handlerMethodsInitialized(getHandlerMethods());
}
  • isHandler方法其实很简单,如下
@Override
protected boolean isHandler(Class<?> beanType) {
  return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
        (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
}
  • 就是判断当前bean定义是否带有Controlller注解或RequestMapping注解,看了这里逻辑可能会想如果只有RequestMapping会生效吗?答案是不会的,因为在这种情况下Spring初始化的时候不会把该类注册为Spring bean,遍历beanNames时不会遍历到这个类,所以这里把Controller换成Compoent注解也是可以,不过一般不会这么做。当确定bean为handlers后,便会从该bean中查找出具体的handler方法(也就是我们通常定义的Controller类下的具体定义的请求处理方法),查找代码如下
protected void detectHandlerMethods(final Object handler) {
  //获取到当前Controller bean的class对象
  Class<?> handlerType = (handler instanceof String) ?
        getApplicationContext().getType((String) handler) : handler.getClass();
  //同上,也是该Controller bean的class对象
  final Class<?> userType = ClassUtils.getUserClass(handlerType);
  //获取当前bean的所有handler method。这里查找的依据便是根据method定义是否带有RequestMapping注解。如果有根据注解创建RequestMappingInfo对象
  Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
      public boolean matches(Method method) {
        return getMappingForMethod(method, userType) != null;
      }
  });
  //遍历并注册当前bean的所有handler method
  for (Method method : methods
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值