Spring MVC 中使用 PathPattern 进行 URL 匹配

工程 | Rossen Stoyanchev | 2020年6月30日 | ...

最近发布的 Spring Framework 5.3 M1 公告 中提到“Spring MVC 带有 PathPattern 解析,可实现高效的 URL 匹配”。本文将在此基础上提供更多上下文和细节。

概述

在 Spring 应用程序中,AntPathMatcher 用于识别 Spring 配置中的类路径、文件系统、远程和其他资源。它也一直用于 Spring MVC 中匹配 URL 路径。随着时间的推移,Web 应用程序中模式的数量和语法不断增长,AntPathMatcher 也在不断发展以满足这些需求,但一些痛点仍然没有解决。

  1. 在 Web 应用程序中,每个请求都需要匹配多次模式,因此性能和效率的任何提升都很重要。但是,String 模式匹配限制了可以实现的目标。

  2. 多年来,在多个与请求匹配的模式中选择最具体的模式一直具有挑战性,如果没有简单的方法使其更具可预测性,而不会影响其他情况。

  3. String 路径与 String 模式进行匹配使得难以避免 URI 编码问题。例如,是否应该首先对传入路径进行解码,然后进行匹配?这样可以声明模式本身不包含编码字符,但如果请求路径包含 %2F%3B(分别为 /;)会怎样?解码后,这些字符会改变路径的结构,从而难以可靠地进行匹配。我们可以通过 UrlPathHelper#urlDecode 保持请求路径编码,但随后我们无法使用前缀 Servlet 映射,因为 servletPath 本身已解码,并且我们的模式也需要编码。

  4. 路径参数也提出了类似的挑战。可以在匹配前移除它们,但如果我们想通过 @MatrixVariable 提取它们怎么办?我们可以使用 UrlPathHelper#removeSemicolonContent 将它们保留在路径中,但现在模式必须考虑路径参数。

PathPattern

在 Spring Framework 5.0 中引入 Spring WebFlux 是重新思考所有这些问题并创建替代方案的一个好机会。这导致了解析的 PathPattern 的创建,该模式与表示 URL 路径的解析的 PathContainer 进行匹配。

模式在启动时进行解析,并在运行时重复使用,以实现高效的 URL 匹配。效率提高了多少?如果没有具体的用例,很难给出具体数字,但我们的 jmh 基准测试 显示吞吐量提高了 6-8 倍,分配率降低了 30-40%。您可以调整基准测试以获得更符合您应用程序的数字。

PathPatternAntPathMatcher 语法兼容,除了以下几点:

  1. 支持其他语法以匹配和捕获结尾处的 0 个或多个路径段,例如 "/foo/{*spring}"。这在 REST API 中作为通配符模式非常有用,可以通过 @PathVariable 访问捕获的路径段。

  2. 仅允许在模式末尾使用 "**" 进行多段匹配。这有助于消除在为给定请求选择最接近的匹配项时的大多数歧义原因。

PathContainer 有助于解决其余问题。例如,它从不解码完整路径,而是将其分解并分别解码路径段,同时移除路径参数,并将生成的解码和规范化值逐个匹配。因此,编码的 "/"";" 不会改变路径的结构,并且路径参数仍然可用。这意味着无需配置请求路径的解析方式,也不需要考虑权衡取舍。

Spring MVC 和 PathPattern

从 Spring Framework 5.3 开始,Spring MVC 支持使用 PathPattern,所有 HandlerMapping 实现都公开了一个属性来设置 PathPatternParser 作为使用 AntPathMatcher 的替代方案。启用此功能最简单的方法是在 MVC 配置的 路径匹配 选项中配置 PathPatternParser

反过来,如果 DispatcherServlet 检测到任何启用了解析模式的 HandlerMapping,它将在运行时解析 URL 路径,并在一个众所周知的请求属性下提供它。也可以使用 ServletRequestPathFilter 更早地执行此操作,在这种情况下,DispatcherServlet 将不再再次解析它。

PathPattern 和 AntPathMatcher 的混合使用

在某些情况下,可以启用一个使用解析模式的 HandlerMapping,另一个使用 AntPathMatcher。例如,第三方库可以注册其自己的 HandlerMapping bean,而未启用解析模式。虽然每个 HandlerMapping 都独立执行自己的匹配,但其他组件(如拦截器)需要能够支持和使用解析的 RequestPathPathPatternString lookupPathAntPathMatcher,具体取决于哪个可用。

这就是为什么从 5.3 开始,此类组件使用 ServletRequestPathUtils 来检查哪个可用,并相应地使用 PathPatternAntPathMatcher。在大多数情况下,应用程序不需要担心这一点,并且模式语法在很大程度上是相同的,因此它应该可以正常工作。

后缀模式匹配

相关地,在 5.3 中,默认情况下已关闭使用后缀模式匹配以及 Spring MVC 中通过路径扩展进行内容协商的其他选项。多年来,这在许多方面都被证明是有问题的。这就是为什么在使用 PathPatternParser 时甚至不支持它的原因。即使在 5.3 中使用 AntPathMatcher,如果要继续使用这些选项,也需要重新启用它们。

总之,我们希望 Spring MVC 应用程序切换到使用 PathPattern 而不是 AntPathMatcher,以利用效率提升、改进的语法以及更可预测的处理 URL 路径问题的方式。请使用您自己的应用程序试用 M1,也许通过基准测试运行它,并让我们知道您的任何反馈。

获取 Spring 时事通讯

通过 Spring 时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部