springMVC源码探索之RequestMappingHandlerMapping

简介: springMVC源码探索之RequestMappingHandlerMapping

RequestMappingHandlerMapping

简介

RequestMappingHandlerMapping是AbstractHandlerMethodMapping 抽象类的唯一实现类,它的作用 是根据在Controller中的@RequestMapping注解生成RequestMappingInfo。

方法

上一篇在记录AbstractHandlerMethodMapping源码是有出现过一些方法,AbstractHandlerMethodMapping是抽象类这些方法的具体实现都在子类RequestMappingHandlerMapping 中。

detectHandlerMethods

AbstractHandlerMethodMapping#detectHandlerMethods() 这个方法的作用是从handler中获取handler method并注册。detectHandlerMethods 有些方法是需要RequestMappingHandlerMapping 实现的,相关方法会在下面介绍。

/**
   * Look for handler methods in a handler.
   * @param handler the bean name of a handler or a handler instance
   */
  protected void detectHandlerMethods(final Object handler) {
    Class<?> handlerType = (handler instanceof String ?
        obtainApplicationContext().getType((String) handler) : handler.getClass());
    if (handlerType != null) {
      //为给定的类返回用户定义的类:通常只是给定的类,如果是cglib生成的子类,则返回原始的类。
      final Class<?> userType = ClassUtils.getUserClass(handlerType);
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
          (MethodIntrospector.MetadataLookup<T>) method -> {
            try {
              // 为处理程序方法提供映射
              return getMappingForMethod(method, userType);
            }
            catch (Throwable ex) {
              throw new IllegalStateException("Invalid mapping on handler class [" +
                  userType.getName() + "]: " + method, ex);
            }
          });
      if (logger.isDebugEnabled()) {
        logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
      }
      // 为查找到的handler method 进行注册
      methods.forEach((method, mapping) -> {
        Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
        registerHandlerMethod(handler, invocableMethod, mapping);
      });
    }
  }

afterPropertiesSet

初始化bean是调用的方法,各种配置设置并调用父类afterPropertiesSet 方法。

@Override
  public void afterPropertiesSet() {
  // 各种配置设置
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    // 调用AbstractHandlerMethodMapping afterPropertiesSet 方法
    super.afterPropertiesSet();
  }

isHandler

isHandler 方法作用是判断提供的handler是否有@Controller或@RequestMapping注解

/**
   * {@inheritDoc}
   * <p>Expects a handler to have either a type-level @{@link Controller}
   * annotation or a type-level @{@link RequestMapping} annotation.
   */
  @Override
  protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
        AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
  }

getMappingForMethod

通过@RequestMapping 注解生成一个RequestMappingInfo 对象并返回,如果没有使用RequestMapping 注解会返回null,主要还是看createRequestMappingInfo 方法

@Override
  @Nullable
  protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
        info = typeInfo.combine(info);
      }
    }
    return info;
  }

createRequestMappingInfo

createRequestMappingInfo 解析RequestMapping 注解 生成RequestMappingInfo对象。

createRequestMappingInfo(AnnotatedElement element)这个方法会先判断参数类型,然后根据类型去查找是否有额外的请求条件,如果有就把条件RequestMapping 和 条件做为参数调用重载方法

createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition);

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    // getCustomTypeCondition 和 getCustomMethodCondition return null 
    RequestCondition<?> condition = (element instanceof Class ?
        getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
  }

getCustomTypeCondition和getCustomMethodCondition 这两个方法没有实现,它们的作用是自定义请求参数条件,如果需要可以继承AbstractRequestCondition 和使用CompositeRequestCondition 类来提供多个自定义条件。


重载方法createRequestMappingInfo,实际生成RequestMappingInfo 的方法,

/**
   * Create a {@link RequestMappingInfo} from the supplied
   * {@link RequestMapping @RequestMapping} annotation, which is either
   * a directly declared annotation, a meta-annotation, or the synthesized
   * result of merging annotation attributes within an annotation hierarchy.
   */
  protected RequestMappingInfo createRequestMappingInfo(
      RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
    RequestMappingInfo.Builder builder = RequestMappingInfo
        .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
        .methods(requestMapping.method())
        .params(requestMapping.params())
        .headers(requestMapping.headers())
        .consumes(requestMapping.consumes())
        .produces(requestMapping.produces())
        .mappingName(requestMapping.name());
    if (customCondition != null) {
      builder.customCondition(customCondition);
    }
    return builder.options(this.config).build();
  }

上面就是简单的介绍了一下springmvc路径映射过程,有兴趣的还是看下源码吧,

能力有限,水平一般,如有错误,请多指出。

目录
相关文章
|
2月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
42 0
|
2月前
|
Java 应用服务中间件 数据库连接
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
36 0
|
4月前
|
设计模式 前端开发 Java
[Spring ~源码] Spring的run方法以及SpringMVC执行流程
[Spring ~源码] Spring的run方法以及SpringMVC执行流程
|
9月前
|
存储 前端开发 搜索推荐
(八)Spring源码解析:Spring MVC
(八)Spring源码解析:Spring MVC
54 1
|
4月前
|
SQL JSON 前端开发
【源码免费下载】SpringBoot整合Spring+SpringMVC+MyBatisPlus案例:图书管理系统
【源码免费下载】SpringBoot整合Spring+SpringMVC+MyBatisPlus案例:图书管理系统
64 0
|
前端开发 Java Spring
源码浅析SpringMVC请求的流转过程
Spring MVC框架使用了其”模型-视图-控制器”( Model-View-Controller )架构方式,用于开发灵活且松散耦合的 Web 应用程序。我们都使用过SpringMVC来处理信息,并渲染视图到Browser。但需要注意的是,在现在的架构中,大都采用了前后端分离的情况,而我们在使用SpringMVC的时候,只需要关注M(Model),C(Controller)这两个部分,而视图渲染的部分则交给了前端。
286 0
源码浅析SpringMVC请求的流转过程
|
JSON 缓存 Java
享读SpringMVC源码5-异常处理HandlerExceptionResolver(下)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(下)
|
Java Spring 容器
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
|
Java Spring
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
|
数据采集 缓存 Java
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(上)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(上)