Spring 5 has also been out for a long time, there are some new things we need to explore slowly. Recently, when I was looking at the SpringMVC source code, I saw the following piece of code.
|
|
This code initializes the path used for RequestMapping
with a string pattern match performed by PathMatcher
.
This is a method in the AbstractHandlerMapping
abstract class, which plays a key role in Spring WebFlux
, for URL matching. I was curious: wasn’t this always the job of AntPathMatcher
? I’ve used it before when I was learning Spring Security
.
This method is new in Spring5, there was no such method before. In the old SpringMVC, when we need to get the current request path, we directly get it by the following way.
|
|
But now it has changed and now gets the current request path in the following way.
|
|
The main difference between the two ways is that the initLookupPath
method has an additional usesPathPatterns
option, which is new in Spring5 and is especially important if you use WebFlux in your project! Because WebFlux only has the PathPattern
pattern, not the AntPathMatcher
.
The software versions used in this article are as follows.
- SpringBoot:
2.4.2
- JDK:
8
- Spring Framework:
5.3.19
AntPathMatcher
When we use the @RequestMapping
annotation to mark the request interface (or use its similar methods like @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping
), we can use some wildcard characters to match URL address, for a simple example, suppose I have the following five handler methods.
|
|
The meanings of several wildcard characters are as follows.
Wildcard | Meaning |
---|---|
** |
Match 0 or more directories |
* |
Match 0 or more characters |
? |
Match any single character |
Now that we know what wildcards mean, let’s talk about what requests each handler method can match.
- The first method, can take requests like
/hello/123/123/hello
,/hello/a/hello
, and/hello/hello
, because the**
in between represents 0 or more directories. - The second method, which can receive requests such as
/hallo
,/hello
,/hMllo
, note that it cannot receive/haallo
or/hllo
, because?
represents a character. - The third method can receive any request with a
.html
suffix, such as/aaa/bb/cc.html
,/aa.html
or/aa/aa.html
. - The fourth method, which we are all familiar with, is used by everyone in RESTful-style api design, and receives requests in a format similar to
/hello/aa/bb
, where parameter p1 corresponds to aa and parameter p2 corresponds to bb. - The fifth method uses a regular pattern, with the name, version and ext parameters expressed as a regular pattern, and it can receive requests such as
/spring-web-3.0.5.jar
, where the final parameter name isspring-web
, version is3.0.5
and ext is. jar
.
This is a feature that existed in SpringMVC before, whether you used it or not, it exists consistently anyway.
So who supports this feature? It’s the AntPathMatcher
.
AntPathMatcher
is a path matcher that implements the Ant style.
The Ant-style path rules are actually the same three path matching strings we introduced in the code above, which is very simple. This path matching rule comes from the Apache Ant project, which is rarely used anymore, and its replacement is the well-known Maven.
If you are lucky enough to maintain some old projects from before 2010, you may come across Ant.
AntPathMatcher
is actually very widely used in SpringMVC, not only in @RequestMapping
, but also in other places where path matching is involved, for example, when we configure static resource filtering in the SpringMVC configuration file, it is also Ant style path matching.
|
|
Ant-style path matchers are also used for interceptor path registration, cross-domain path matching, and so on.
Overall, AntPathMatcher
is a relatively primitive path matching solution in Spring, which is simple but inefficient and inconvenient when dealing with URL encoding.
As a result, Spring5 has introduced PathPattern
.
PathPattern
PathPattern
is designed for web applications and is mostly similar to the previous AntPathMatcher
, but there are some minor differences
If it is a Servlet
application, the official recommended URL matching solution is PathPattern
(of course you can also choose the older AntPathMatcher
), although the official recommendation is PathPattern
, the default is still AntPathMatcher
; if you are using WebFlux
, PathPattern
is the only solution.
Note that PathPattern is a very new thing. Before Spring 5.3, we were limited to AntPathMatcher
in our Servlet applications, and since Spring 5.3, we can use PathPattern
.
PathPattern
pre-parses URL rules into PathContainer
, which is much faster for URL path matching, and the difference between PathPattern
and AntPathMatcher
is mainly in two aspects.
-
PathPattern
only supports the use of**
at the end, if you use**
in the middle of the path, it will throw an exception. The first and third methods above will throw exceptions in PathPattern mode. -
PathPattern
supports path matching using a method such as{*path}
. This way of writing can also match to multi-level paths and assign the matched values to path variables.Take the following path as an example.
If the request path is
http://localhost:8080/path/aa
, then the value of the path parameter is/aa
.If the request path is
http://localhost:8080/path/aa/bb/cc/dd
, then the value of the path parameter is/aa/bb/cc/dd
.This is also relatively new, as it was not in the previous
AntPathMatcher
.
We know that /**
and /{*pathVariable}
both have the “ability” to match all remaining paths, but what is the difference between them?
/**
can match successfully, but can’t get the value of the dynamically successful matched element/{*pathVariable}
can be considered as an enhanced version of/**
: it can get the value of this part of the dynamically successful match
Since both /**
and /{*pathVariable}
have the ability to match the remaining paths, what is the priority relationship between them if they are put together?
|
|
The output is as follows.
|
|
When testing, I put /{*pathVariable}
into set first and /**
later, but in the end, /**
comes first.
Conclusion: When both appear at the same time (there is a conflict), /**
matches first.
How to use PathPattern in your application
By default, AntPathMatcher
is still used in SpringMVC, so how to enable PathPattern
? It’s easy, just add the following configuration to your SpringBoot project.
After adding this configuration, in the code posted at the beginning of our article, it goes to the if branch, which in turn uses PathPattern
to parse the request URL.
Starting with Spring Boot 2.6 the default strategy for matching request paths to Spring MVC processing maps has been changed from
AntPathMatcher
toPathPatternParser
. you can setspring.mvc.pathmatch.matching-strategy
toant-path-matcher
to change it.
PathPattern
removes the Ant character, but maintains good backward compatibility: except for not supporting writing **
in the middle of the path, all other matching rules remain the same behavior as AntPathMatcher
, and also adds powerful support for {*pathVariable}
.
PathPattern
syntax is more suitable for web applications, non-Web environments still have one and only one option, which is AntPathMatcher
, because PathPattern
is designed for Web environments and cannot be used in non-Web environments. So path matching scenarios like resource loading, package scanning, etc. are still left to AntPathMatcher
to complete.
Reference http://www.enmalvi.com/2022/09/06/springmvc-pathpattern/