SpringMVC源码解读之HandlerMapping – AbstractUrlHandlerMapping系列request分发

简介

在Spring MVC中,HandlerMapping是一个非常重要的组件,它负责将请求分发给对应的处理器。AbstractUrlHandlerMappingHandlerMapping的一个实现类,它通过URL映射规则来确定请求应该由哪个处理器来处理。本文将详细介绍AbstractUrlHandlerMapping的源码实现,并提供两个示例说明。

AbstractUrlHandlerMapping源码解读

AbstractUrlHandlerMappingHandlerMapping的一个抽象实现类,它提供了一些通用的方法和属性,如urlMaporderpathMatcher等。以下是AbstractUrlHandlerMapping的源码实现。

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
  private Map<String, Object> urlMap = new LinkedHashMap<>();
  private UrlPathHelper urlPathHelper = new UrlPathHelper();
  private PathMatcher pathMatcher = new AntPathMatcher();
  private boolean useTrailingSlashMatch = true;
  private boolean lazyInitHandlers = false;

  public void setUrlMap(Map<String, ?> urlMap) {
    this.urlMap = new LinkedHashMap<>(urlMap);
  }

  public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
    this.urlPathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
  }

  public void setPathMatcher(PathMatcher pathMatcher) {
    this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
  }

  public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
    this.useTrailingSlashMatch = useTrailingSlashMatch;
  }

  public void setLazyInitHandlers(boolean lazyInitHandlers) {
    this.lazyInitHandlers = lazyInitHandlers;
  }

  @Override
  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
      handler = getDefaultHandler();
    }
    return handler;
  }

  protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    Object handler = this.urlMap.get(urlPath);
    if (handler == null) {
      handler = lookupHandler(urlPath, request.getMethod());
    }
    return handler;
  }

  protected Object lookupHandler(String urlPath, String httpMethod) throws Exception {
    List<Object> matchingHandlers = new ArrayList<>();
    for (Map.Entry<String, Object> entry : this.urlMap.entrySet()) {
      String mappedPath = entry.getKey();
      Object handler = entry.getValue();
      if (this.pathMatcher.match(mappedPath, urlPath)) {
        if (handler instanceof String) {
          handler = getApplicationContext().getBean((String) handler);
        }
        matchingHandlers.add(handler);
      }
    }
    if (!matchingHandlers.isEmpty()) {
      if (matchingHandlers.size() > 1) {
        matchingHandlers = sortMatchingHandlers(matchingHandlers, urlPath, httpMethod);
      }
      return matchingHandlers.get(0);
    }
    return null;
  }

  protected List<Object> sortMatchingHandlers(List<Object> matchingHandlers, String lookupPath, String httpMethod) {
    if (matchingHandlers.size() > 1) {
      Comparator<Object> comparator = new RequestMappingInfoHandlerMethodMappingNamingComparator(this.pathMatcher, lookupPath);
      if (this.order != null) {
        comparator = new OrderComparator().compare(comparator, this.order);
      }
      if (this.useTrailingSlashMatch) {
        comparator = new TrailingSlashHandlerMappingComparator(lookupPath).compare(comparator, null);
      }
      Collections.sort(matchingHandlers, comparator);
    }
    return matchingHandlers;
  }
}

在上面的源码中,我们可以看到AbstractUrlHandlerMapping定义了一些属性和方法,如urlMapurlPathHelperpathMatcheruseTrailingSlashMatchlazyInitHandlers等。其中,urlMap是一个Map对象,用于存储URL映射规则和对应的处理器;urlPathHelper是一个UrlPathHelper对象,用于获取请求的URL路径;pathMatcher是一个PathMatcher对象,用于匹配URL路径和映射规则;useTrailingSlashMatch表示是否使用尾部斜杠匹配;lazyInitHandlers表示是否延迟初始化处理器。

getHandlerInternal()方法中,我们可以看到AbstractUrlHandlerMapping使用urlPathHelper获取请求的URL路径,并调用lookupHandler()方法查找对应的处理器。如果找不到对应的处理器,则返回默认的处理器。

lookupHandler()方法中,我们可以看到AbstractUrlHandlerMapping首先从urlMap中查找是否有对应的处理器,如果没有,则调用lookupHandler(String urlPath, String httpMethod)方法查找对应的处理器。在lookupHandler(String urlPath, String httpMethod)方法中,AbstractUrlHandlerMapping遍历urlMap中的所有映射规则,使用pathMatcher匹配URL路径和映射规则,找到匹配的处理器后,将其添加到matchingHandlers列表中。如果matchingHandlers列表不为空,则调用sortMatchingHandlers()方法对处理器进行排序,并返回第一个处理器。

示例1:使用AbstractUrlHandlerMapping处理HTTP GET请求

以下是一个使用AbstractUrlHandlerMapping处理HTTP GET请求的示例。

public class HelloController implements Controller {
  @Override
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ModelAndView modelAndView = new ModelAndView("hello");
    modelAndView.addObject("message", "Hello, World!");
    return modelAndView;
  }
}

public class HelloHandlerMapping extends AbstractUrlHandlerMapping {
  public HelloHandlerMapping() {
    setUrlMap(Collections.singletonMap("/hello", new HelloController()));
    setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

public class HelloWebApplicationInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(HelloHandlerMapping.class);
    context.setServletContext(servletContext);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
  }
}

在上面的示例中,我们首先定义了一个HelloController类,它实现了Controller接口,并在handleRequest()方法中返回一个ModelAndView对象。然后,我们定义了一个HelloHandlerMapping类,它继承了AbstractUrlHandlerMapping类,并在构造函数中使用setUrlMap()方法设置了URL映射规则和对应的处理器。最后,我们定义了一个HelloWebApplicationInitializer类,它实现了WebApplicationInitializer接口,并在onStartup()方法中注册了HelloHandlerMapping类和DispatcherServlet

示例2:使用AbstractUrlHandlerMapping处理HTTP POST请求

以下是另一个使用AbstractUrlHandlerMapping处理HTTP POST请求的示例。

public class CalculatorController implements Controller {
  @Override
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    int a = Integer.parseInt(request.getParameter("a"));
    int b = Integer.parseInt(request.getParameter("b"));
    int result = a + b;
    ModelAndView modelAndView = new ModelAndView("result");
    modelAndView.addObject("result", result);
    return modelAndView;
  }
}

public class CalculatorHandlerMapping extends AbstractUrlHandlerMapping {
  public CalculatorHandlerMapping() {
    setUrlMap(Collections.singletonMap("/calculator", new CalculatorController()));
    setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

public class CalculatorWebApplicationInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(CalculatorHandlerMapping.class);
    context.setServletContext(servletContext);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
  }
}

在上面的示例中,我们首先定义了一个CalculatorController类,它实现了Controller接口,并在handleRequest()方法中获取请求参数ab,计算结果后返回一个ModelAndView对象。然后,我们定义了一个CalculatorHandlerMapping类,它继承了AbstractUrlHandlerMapping类,并在构造函数中使用setUrlMap()方法设置了URL映射规则和对应的处理器。最后,我们定义了一个CalculatorWebApplicationInitializer类,它实现了WebApplicationInitializer接口,并在onStartup()方法中注册了CalculatorHandlerMapping类和DispatcherServlet

总结

本文详细介绍了AbstractUrlHandlerMapping的源码实现,并提供了两个示例说明。我们首先介绍了AbstractUrlHandlerMapping的属性和方法,如urlMapurlPathHelperpathMatcheruseTrailingSlashMatchlazyInitHandlers等。然后,我们提供了一个使用AbstractUrlHandlerMapping处理HTTP GET请求的示例和一个使用AbstractUrlHandlerMapping处理HTTP POST请求的示例。通过本文的介绍,我们可以了解到如何在Spring MVC应用程序中使用AbstractUrlHandlerMapping来分发请求。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringMVC源码解读之HandlerMapping – AbstractUrlHandlerMapping系列request分发 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • Java文件操作类 File实现代码

    一、File类概述 在Java编程中,经常需要对文件进行操作,比如读写文件内容、创建或删除文件等。Java中提供了一个File类,能够完成文件的相关操作。 File类是用来表示一个文件或者目录(文件夹)的抽象路径名。在实际使用中需要注意,File对象表示的是在代码中的抽象概念,并不一定要对应实际存在的文件或目录。 在Java中使用File类时,需要先创建一个…

    Java 2023年5月20日
    00
  • jQuery EasyUI 布局之动态添加tabs标签页

    jQuery EasyUI是一个基于jQuery的UI插件集,提供了多种易用且功能强大的UI组件,其中包含布局组件,如Accordion、Tabs、Panel、Layout等。本文将详细讲解如何使用jQuery EasyUI布局组件中的Tabs,并通过动态添加Tabs标签页的方式来实现内容与标签页之间的切换。 准备工作 首先,需要引入jQuery EasyU…

    Java 2023年6月15日
    00
  • java中Class类的基础知识点及实例

    Java中Class类的基础知识点及实例 Class类的概念 Class 类是 Java 中用于描述类类型的类,它是所有类、接口、数组在内存中的一个表示。Class 对象是在类被加载的时候创建的,它保存了类的相关信息,例如类的名称、类的成员变量、类的方法等。 通过 Class 对象,我们可以对类进行一些操作,例如创建该类的实例、获取它所包含的方法以及构造函数…

    Java 2023年5月26日
    00
  • Java实现简单的五子棋游戏示例代码

    一、介绍 五子棋是一种非常古老的中国传统游戏,它简单易懂,规则简单,同时又非常有趣,是大众化的棋类游戏之一。本文将介绍如何用 Java 语言实现一个简单的五子棋游戏,让小伙伴们体验一下自己编写游戏的快感。 二、准备工作 开发五子棋游戏需要熟悉 Java 语言的基础代码编写,同时需要掌握一些基础的图形界面编程知识,推荐使用 Swing 或 JavaFX 进行图…

    Java 2023年5月19日
    00
  • Spring Security整合CAS的示例代码

    下面是我对于Spring Security整合CAS的示例代码的攻略: 前置知识 在开始讲解Spring Security整合CAS的示例代码之前,需要先了解以下几个概念: CAS (Central Authentication Service) CAS是一个单点登录协议,可以让用户在多个Web应用中进行统一认证和授权。对于用户进行登录的请求,CAS服务会将…

    Java 2023年5月20日
    00
  • C语言与java语言中关于二维数组的区别

    C语言和Java语言在二维数组的定义和使用方面存在一些区别,下面我将分别对它们的二维数组进行详细讲解。 C语言中的二维数组 定义 在C语言中,二维数组可以被定义为由多个一维数组组成的数组,每个一维数组又由多个元素组成。二维数组的定义和初始化可以通过以下方式进行: // 定义一个3行4列的二维数组 int a[3][4] = { {1, 2, 3, 4}, {…

    Java 2023年5月26日
    00
  • Java各种排序算法汇总(冒泡,选择,归并,希尔及堆排序等)

    Java各种排序算法汇总 本文将详细讲解Java中常见的各种排序算法,包括冒泡排序、选择排序、归并排序、希尔排序、堆排序等,以及他们的实现代码和时间复杂度分析。 冒泡排序 冒泡排序是一种基础的排序算法,核心思想是将相邻的元素两两比较,将较大的元素向后移动。代码如下: public static void bubbleSort(int[] array) { f…

    Java 2023年5月19日
    00
  • Java实现发送手机短信语音验证功能代码实例

    下面是Java实现发送手机短信语音验证功能代码实例的完整攻略。 1. 准备工作 首先需要在云通讯官网https://www.yuntongxun.com/注册账号,然后创建应用,并获取相应的Account SID 和 Auth Token。同时还需要在应用中开通语音验证码功能,并记录下相应的模板ID。 2. 引入SDK 使用云通讯提供的Java SDK来发送…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部