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日

相关文章

  • Docker构建Maven+Tomcat基础镜像的实现

    下面是 Docker 构建 Maven + Tomcat 基础镜像的实现攻略。 1. 安装 Docker 在开始之前,首先需要在本地安装 Docker。具体的安装过程可以参考 Docker 官方文档。 2. 准备 Maven + Tomcat 打包好的 war 包 在构建 Docker 镜像之前,需要准备好 Maven + Tomcat 打包好的 war 包…

    Java 2023年6月2日
    00
  • Java生成和解析XML格式文件和字符串的实例代码

    下面我将详细讲解“Java生成和解析XML格式文件和字符串的实例代码”的完整攻略以及其中的两个示例。 1. 什么是XML XML是可扩展标记语言(Extensible Markup Language)的缩写,它是一种用于传输和存储数据的标准格式。XML是自我描述、可扩展的,可以通过文本编辑器或工具生成并解析。在Java应用程序中,XML是一种常见的数据交换格…

    Java 2023年5月20日
    00
  • Struts2相关的面试题整理分享

    下面是Struts2相关的面试题整理分享的完整攻略。 1. Struts2简介 Struts2是一个基于MVC设计模式的Web开发框架,它基于Java Servlet技术,可以帮助开发者更方便地创建Web应用程序。 1.1 MVC架构 MVC架构将应用程序分为3个主要部分: Model:应用程序数据及其处理 View:用户界面的展示 Controller:接…

    Java 2023年5月20日
    00
  • 解决对接JAVA SM2加密遇到的坑

    解决对接JAVA SM2加密遇到的坑 在对接JAVA SM2加密过程中,有时会遇到一些问题,本文将为大家提供解决这些问题的攻略。 问题一:SM2加密时长度不一致 当使用SM2加密时,出现明文长度和加密后密文长度不一致的情况,这是因为在加密过程中,SM2算法会使用填充算法将明文进行填充。在JAVA中,使用了PKCS7Padding填充,而在其他语言中可能使用的…

    Java 2023年5月20日
    00
  • Java调用接口如何获取json数据解析后保存到数据库

    要实现Java调用接口获取JSON数据并将其解析后保存到数据库,我们可以按下面的步骤进行操作: 1.发送HTTP请求获取JSON数据 使用Java的HttpUrlConnection或HttpClient等工具发送HTTP请求,获取返回的JSON字符串。 示例代码: String apiUrl = "https://api.example.com/…

    Java 2023年5月26日
    00
  • JS注释所产生的bug 即使注释也会执行

    JS注释所产生的bug是指在一些情况下,即使代码中存在注释,这些注释也会被执行而导致程序出现问题。 该问题主要是因为在一些JS引擎中,被注释的代码可能在编译阶段和解析阶段都会被执行,因此如果注释中包含了有效的代码,则这些代码会被直接执行。这就引起了一定的安全隐患,也可能导致代码出现逻辑错误。 下面通过两个示例来说明该问题: 示例一: function tes…

    Java 2023年6月15日
    00
  • java实现LRU缓存淘汰算法的方法

    Java实现LRU缓存淘汰算法的方法 什么是LRU缓存淘汰算法? LRU(Least Recently Used)是一种基于时间局部性原理的缓存置换策略,常用于CPU缓存、数据库缓存等场景。它的核心思想是:对于长期未被使用的缓存数据,它们被淘汰的概率更大。 在实际应用中,我们通常将缓存数据存储在一个链表中,每当我们访问缓存数据时,就将该数据移动到链表的头部,…

    Java 2023年5月19日
    00
  • java 使用poi动态导出的操作

    下面就对Java使用poi动态导出的操作进行详细讲解,其中包括使用示例。 什么是POI Apache POI(Poor Obfuscation Implementation)是Apache软件基金会的开源项目,它是用Java实现的对Microsoft Office格式档案读和写的Java类库。POI提供了 API 给Java程序对Microsoft Offi…

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