spring MVC源码探索之AbstractHandlerMethodMapping

简介: spring MVC源码探索之AbstractHandlerMethodMapping

为什么看源码

这篇文章是第一个原因Spring MVC controller路径是否能重复?

第二个就是工作这么多年虽然看过一点框架源码,但是没有系统的看过,写上篇文章的时候看了源码,感觉还挺有意思就记录一下。

第三个就是一直都是在用也该了解一下原理了,至于框架的设计思路、大牛的想法什么的希望能在看源码的过程中学习到。

AbstractHandlerMethodMapping

官方解释是这样的。

/**
 * Abstract base class for {@link HandlerMapping} implementations that define
 * a mapping between a request and a {@link HandlerMethod}.
 *
 * <p>For each registered handler method, a unique mapping is maintained with
 * subclasses defining the details of the mapping type {@code <T>}.
 * @param <T> The mapping for a {@link HandlerMethod} containing the conditions
 * needed to match the handler method to incoming request.
 */
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean 

我的理解为AbstractHandlerMethodMapping为每个注册的handler method,对于每个子类映射类型都维护着其唯一的一个映射,就是维护handler method 和URL的关系。主要用于@Controller,@RequestMapping 等注解


AbstractHandlerMethodMapping 实现了InitializingBean接口,InitializingBean是在程序启动的时候执行其唯一的afterPropertiesSet()方法,那我们就先看一下启动时候的要做哪些操作。


initHandlerMethods()

/**
      在初始化的时候发现 handler methods
  * Detects handler methods at initialization.
   */
  @Override
  public void afterPropertiesSet() {
    initHandlerMethods();
  }

在项目启动时会执行initHandlerMethods方法,它的主要功能是扫描应用上下文,发现并注册handler methods。

/**
   * Scan beans in the ApplicationContext, detect and register handler methods.
   * @see #isHandler(Class)
   * @see #getMappingForMethod(Method, Class)
   * @see #handlerMethodsInitialized(Map)
   */
  protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
      logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    // 获取IOC容器中所有bean
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
        BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
        obtainApplicationContext().getBeanNamesForType(Object.class));
    for (String beanName : beanNames) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
        Class<?> beanType = null;
        try {
          beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
          // An unresolvable bean type, probably from a lazy bean - let's ignore it.
          if (logger.isDebugEnabled()) {
            logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
          }
        }
        // 判断bean 是否有Controller 注解或者RequestMapping 注解
        if (beanType != null && isHandler(beanType)) {
          detectHandlerMethods(beanName);
        }
      }
    }
    handlerMethodsInitialized(getHandlerMethods());
  }

isHandler()

AbstractHandlerMethodMapping#isHandler()

RequestMappingHandlerMapping 是目前为止AbstractHandlerMethodMapping的子类中唯一实现了isHandler()方法的子类,看下实现

protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
        AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
  }

isHandler()方法在这里的作用就是检查beanType是否有@Controller或@RequestMapping注解,这两个注解经常使用,应该都很熟悉了。

detectHandlerMethods()

AbstractHandlerMethodMapping#detectHandlerMethods() 这个方法的作用是从handler中获取handler method并注册

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);
      });
    }
  }

registerHandlerMethod()

AbstractHandlerMethodMapping#registerHandlerMethod() 的作用是为每个handler method注册它们唯一的映射路径,源码如下:

/**
   * Register a handler method and its unique mapping. Invoked at startup for
   * each detected handler method.
   * @param handler the bean name of the handler or the handler instance
   * @param method the method to register
   * @param mapping the mapping conditions associated with the handler method
   * @throws IllegalStateException if another method was already registered
   * under the same mapping
   */
  protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
  }

register方法是AbstractHandlerMethodMapping 内部类MappingRegistry里的方法,MappingRegistry是一个注册表,对MappingRegistry有兴趣的可以看一下源码或者看一下我之前的一篇文章 Spring MVC controller路径是否能重复?


我这里只是很简单的记录一下我看的源码,也不全面最好自己能看一下源码。


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


目录
相关文章
|
4天前
|
前端开发 Java 测试技术
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
本文介绍了 `@RequestParam` 注解的使用方法及其与 `@PathVariable` 的区别。`@RequestParam` 用于从请求中获取参数值(如 GET 请求的 URL 参数或 POST 请求的表单数据),而 `@PathVariable` 用于从 URL 模板中提取参数。文章通过示例代码详细说明了 `@RequestParam` 的常用属性,如 `required` 和 `defaultValue`,并展示了如何用实体类封装大量表单参数以简化处理流程。最后,结合 Postman 测试工具验证了接口的功能。
24 0
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
|
4天前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
27 0
|
4天前
|
前端开发 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@PathVariable
`@PathVariable` 是 Spring Boot 中用于从 URL 中提取参数的注解,支持 RESTful 风格接口开发。例如,通过 `@GetMapping(&quot;/user/{id}&quot;)` 可以将 URL 中的 `{id}` 参数自动映射到方法参数中。若参数名不一致,可通过 `@PathVariable(&quot;自定义名&quot;)` 指定绑定关系。此外,还支持多参数占位符,如 `/user/{id}/{name}`,分别映射到方法中的多个参数。运行项目后,访问指定 URL 即可验证参数是否正确接收。
20 0
|
4天前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestMapping
@RequestMapping 是 Spring MVC 中用于请求地址映射的注解,可作用于类或方法上。类级别定义控制器父路径,方法级别进一步指定处理逻辑。常用属性包括 value(请求地址)、method(请求类型,如 GET/POST 等,默认 GET)和 produces(返回内容类型)。例如:`@RequestMapping(value = &quot;/test&quot;, produces = &quot;application/json; charset=UTF-8&quot;)`。此外,针对不同请求方式还有简化注解,如 @GetMapping、@PostMapping 等。
24 0
|
4天前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RestController
本文主要介绍 Spring Boot 中 MVC 开发常用的几个注解及其使用方式,包括 `@RestController`、`@RequestMapping`、`@PathVariable`、`@RequestParam` 和 `@RequestBody`。其中重点讲解了 `@RestController` 注解的构成与特点:它是 `@Controller` 和 `@ResponseBody` 的结合体,适用于返回 JSON 数据的场景。文章还指出,在需要模板渲染(如 Thymeleaf)而非前后端分离的情况下,应使用 `@Controller` 而非 `@RestController`
17 0
|
4月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
152 2
|
2月前
|
SQL Java 数据库连接
对Spring、SpringMVC、MyBatis框架的介绍与解释
Spring 框架提供了全面的基础设施支持,Spring MVC 专注于 Web 层的开发,而 MyBatis 则是一个高效的持久层框架。这三个框架结合使用,可以显著提升 Java 企业级应用的开发效率和质量。通过理解它们的核心特性和使用方法,开发者可以更好地构建和维护复杂的应用程序。
150 29
|
19天前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
|
2月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
123 7
|
3月前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
77 4