Spring MVC启动之HandlerMapping作用及实现详解

 更新时间:2023年03月30日 08:48:28   作者:这堆干货有点猛  
这篇文章主要为大家介绍了Spring MVC启动之HandlerMapping作用及实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

 在上一篇文章中,我们介绍了 Spring MVC 的启动流程,接下来我们将发分多个篇章详细介绍流程中的重点步骤

        今天我们从 HandlerMapping 开始分析,HandlerMapping 是框架中的一个非常重要的组件。它的作用是将URL请求映射到合适的处理程序(Handler)上,这样就能够实现控制器与页面之间的交互。在 Spring MVC 中,有多种不同的 HandlerMapping 实现,本文将对这些实现的作用和源码原理进行详细介绍。

作用

在 Spring MVC 框架中,HandlerMapping 是一个非常重要的组件,它的作用是将URL请求映射到相应的处理程序上。具体来说,HandlerMapping 会根据URL请求的路径、请求参数等信息,确定需要执行哪个处理程序,并将该处理程序返回给 DispatcherServlet。然后 DispatcherServlet 再将请求分配给相应的处理程序,处理程序处理完请求后,将结果返回给 DispatcherServlet,DispatcherServlet 再将结果返回给客户端。

HandlerMapping的实现

        Spring MVC 框架中有多种不同的 HandlerMapping 实现,每种实现都有不同的作用和使用场景。下面将逐一介绍这些实现。

BeanNameUrlHandlerMapping

        BeanNameUrlHandlerMapping 是 Spring MVC 框架中最简单的 HandlerMapping 实现,它的作用是将 URL 请求的路径映射到 Bean 的名称上。具体来说,当请求的路径与一个 Bean 的名称匹配时,BeanNameUrlHandlerMapping 会将该请求映射到对应的 Bean 上。

例如:

假设有一个名为 "/hello" 的请求

我们可以在 Spring 配置文件中定义一个名为 "helloController" 的 Bean

然后使用 BeanNameUrlHandlerMapping 将 "/hello" 请求映射到该 Bean 上

这样,当客户端发送 "/hello" 请求时,DispatcherServlet 就会将该请求分配给 "helloController" 处理。

BeanNameUrlHandlerMapping 的源码比较简单,它的核心代码如下所示:

public class BeanNameUrlHandlerMapping extends AbstractUrlHandlerMapping {
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        return obtainHandler(lookupPath, request);
    }
}

        从代码中可以看出,BeanNameUrlHandlerMapping 实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的 URL 路径查找相应的处理程序

SimpleUrlHandlerMapping

SimpleUrlHandlerMapping 是 Spring MVC 框架中另一种常用的 HandlerMapping 实现,它的作用是将 URL 请求的路径映射到处理程序上。与 BeanNameUrlHandlerMapping 不同的是,SimpleUrlHandlerMapping 可以将一个URL请求映射到多个处理程序上

例如:

假设有两个请求 "/hello" 和 "/world"

我们可以使用 SimpleUrlHandlerMapping 将这两个请求分别映射到不同的处理程序上。具体来说,我们可以在 Spring 配置文件中定义多个 Bean,并分别为它们设置不同的URL路径。

然后使用 SimpleUrlHandlerMapping 将这些URL路径与相应的处理程序进行映射。

这样,当客户端发送一个请求时,SimpleUrlHandlerMapping 就会根据请求的URL路径查找相应的处理程序,并将请求分配给该处理程序处理。

SimpleUrlHandlerMapping 的源码也比较简单,它的核心代码如下所示:

public class SimpleUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        Object handler = lookupHandler(lookupPath, request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        return handler;
    }
}

        从代码中可以看出,SimpleUrlHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口(在 AbstractDetectingUrlHandlerMapping 中继承),并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的URL路径查找相应的处理程序。

ControllerClassNameHandlerMapping

        ControllerClassNameHandlerMapping 是Spring MVC 框架中一种比较特殊的 HandlerMapping 实现,它的作用是将URL请求的路径映射到 Controller 类名上。具体来说,ControllerClassNameHandlerMapping 会根据请求的URL路径查找对应的 Controller 类名,并将该类返回给 DispatcherServlet,然后 DispatcherServlet 再将请求分配给该 Controller 类处理。

例如:

假设有一个名为 "/hello" 的请求

我们可以定义一个名为 HelloController的Controller 类

使用 ControllerClassNameHandlerMapping 将 "/hello" 请求映射到该类上。

这样,当客户端发送 "/hello" 请求时,ControllerClassNameHandlerMapping 就会将该请求映射到 HelloController 处理。

ControllerClassNameHandlerMapping 的源码也比较简单,它的核心代码如下所示:

public class ControllerClassNameHandlerMapping extends AbstractControllerUrlHandlerMapping {
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        String controllerClassName = getClassNameForUrlPath(lookupPath);
        return obtainApplicationContext().getBean(controllerClassName);
    }
}

        从代码中可以看出,ControllerClassNameHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的URL路径查找相应的 Controller 类名,并将该类返回给 DispatcherServlet。

DefaultAnnotationHandlerMapping

        DefaultAnnotationHandlerMapping 是Spring MVC 框架中另一种比较常用的 HandlerMapping实 现,它的作用是将 URL 请求的路径映射到标注了 @RequestMapping 注解的方法上

        具体来说,DefaultAnnotationHandlerMapping 会扫描应用程序中所有标注了 @RequestMapping 注解的方法,并将这些方法与相应的URL路径进行映射。

        然后当客户端发送一个请求时,DefaultAnnotationHandlerMapping 就会根据请求的URL路径查找相应的处理程序,并将该处理程序返回给 DispatcherServlet,然后 DispatcherServlet 再将请求分配给该处理程序处理。

例如:

假设有一个名为 "/hello" 的请求

我们可以在 Controller 类的某个方法上标注 @RequestMapping 注解

将该方法与 "/hello" 请求进行映射。

这样,当客户端发送 "/hello" 请求时,DefaultAnnotationHandlerMapping 就会将该请求映射到该方法上,然后将该方法返回给 DispatcherServlet 处理。

DefaultAnnotationHandlerMapping 的源码比较复杂,因为它需要扫描应用程序中所有标注了 @RequestMapping 注解的方法。其核心代码如下所示:

public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandlerMapping implements BeanFactoryAware, InitializingBean {
    private final List<RequestMappingInfoHandlerMapping> handlerMappings = new ArrayList<>();
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        for (RequestMappingInfoHandlerMapping hm : this.handlerMappings) {
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
    public void afterPropertiesSet() throws Exception {
        initHandlerMethods();
    }
    protected void initHandlerMethods() {
        detectHandlerMethods();
        if (logger.isInfoEnabled()) {
            logger.info("Mapped " + this.handlerMethods.size() + " request handler methods");
        }
    }
    protected void detectHandlerMethods() {
        ...
    }
}

        从代码中可以看出,DefaultAnnotationHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的 URL 路径查找相应的处理程序。

        与其他 HandlerMapping 不同的是,DefaultAnnotationHandlerMapping 还实现了 BeanFactoryAware和InitializingBean 接口,以便在初始化时扫描应用程序中所有标注了 @RequestMapping 注解的方法。

        具体来说,它会调用 detectHandlerMethods 方法,对应用程序中所有标注了 @RequestMapping 注解的方法进行扫描,并将这些方法与相应的URL路径进行映射。

总结

        在 Spring MVC 框架中,HandlerMapping 用于将URL请求的路径映射到相应的处理程序上。框架中提供了多种不同的 HandlerMapping 实现,包括 BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、ControllerClassNameHandlerMapping 和 DefaultAnnotationHandlerMapping 等。不同的HandlerMapping 实现方式适用于不同的应用场景。

  • BeanNameUrlHandlerMapping 是最简单的HandlerMapping实现,它将 URL 请求的路径直接映射到 Bean 的名称上。
  • SimpleUrlHandlerMapping 则将 URL 请求的路径与相应的处理程序进行映射。
  • ControllerClassNameHandlerMapping 将 URL 请求的路径映射到 Controller 类名上。
  • DefaultAnnotationHandlerMapping 则将 URL 请求的路径映射到标注了 @RequestMapping 注解的方法上。

无论是哪种 HandlerMapping 实现方式,它们都遵循相同的流程来处理请求。具体来说,它们的流程如下:

客户端发送请求到DispatcherServlet。

  • DispatcherServlet根据请求的URL路径选择相应的HandlerMapping。
  • HandlerMapping将请求的URL路径与相应的处理程序进行映射。
  • HandlerMapping返回相应的处理程序。
  • DispatcherServlet将请求交给相应的处理程序进行处理。
  • 处理程序进行业务逻辑的处理,并返回相应的结果。
  • DispatcherServlet将处理程序的结果进行封装,并返回给客户端。

以上就是Spring MVC启动之HandlerMapping作用及实现详解的详细内容,更多关于Spring MVC启动HandlerMapping的资料请关注脚本之家其它相关文章!

相关文章

  • IDEA2020.3创建web工程的完整步骤

    IDEA2020.3创建web工程的完整步骤

    这篇文章主要给大家介绍了关于IDEA2020.3创建web工程的完整步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 详解Java高并发编程之AtomicReference

    详解Java高并发编程之AtomicReference

    此篇文章主要介绍了AtomicReference的出现背景,AtomicReference的使用场景,以及介绍了AtomicReference的源码,重点方法的源码分析
    2021-06-06
  • Java编程实现深度优先遍历与连通分量代码示例

    Java编程实现深度优先遍历与连通分量代码示例

    这篇文章主要介绍了Java编程实现深度优先遍历与连通分量代码示例,
    2017-11-11
  • Spring 数据库连接池(JDBC)详解

    Spring 数据库连接池(JDBC)详解

    本篇文章主要介绍了基于Spring的JDBC基本框架搭建;基于Spring的JDBC增删改查;读取配置文件中的数据等,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-05-05
  • mybatis一对多两种mapper写法实例

    mybatis一对多两种mapper写法实例

    这篇文章主要介绍了mybatis一对多两种mapper写法实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • SpringBoot中的Spring Cloud Hystrix原理和用法详解

    SpringBoot中的Spring Cloud Hystrix原理和用法详解

    在Spring Cloud中,Hystrix是一个非常重要的组件,Hystrix可以帮助我们构建具有韧性的分布式系统,保证系统的可用性和稳定性,在本文中,我们将介绍SpringBoot中的Hystrix,包括其原理和如何使用,需要的朋友可以参考下
    2023-07-07
  • MyBatis通用的10种写法总结大全

    MyBatis通用的10种写法总结大全

    这篇文章主要给大家介绍了关于MyBatis通用的10种写法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • mybatis 加载配置文件的方法(两种方式)

    mybatis 加载配置文件的方法(两种方式)

    这篇文章主要介绍了mybatis 加载配置文件的方法,通过实例代码给大家介绍了mybatis 加载配置文件的两种方式,需要的朋友可以参考下
    2017-12-12
  • java实现菜单树的示例代码

    java实现菜单树的示例代码

    这篇文章主要为大家详细介绍了java实现菜单树的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • 一文搞懂Mybatis中Mapper配置文件获取参数的五种方式

    一文搞懂Mybatis中Mapper配置文件获取参数的五种方式

    这篇文章主要介绍了Mybatis中Mapper配置文件获取参数的五种方式,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-03-03

最新评论