Spring5 也曾经进去良久了,里边有一些新玩法也须要咱们去缓缓揭开面纱,这不,松哥最近在钻研 SpringMVC 源码的时候,就看到这样一段代码:
protected String initLookupPath(HttpServletRequest request) {if (usesPathPatterns()) {request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
String lookupPath = requestPath.pathWithinApplication().value();
return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
}
else {return getUrlPathHelper().resolveAndCacheLookupPath(request);
}
}
这个办法就是 Spring5 里边进去的,以前是没有这个办法的。在旧的 SpringMVC 中,当咱们须要获取以后申请地址的时候,间接通过如下形式获取:
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
然而当初变了,当初获取以后申请 URL 地址时,形式如下:
String lookupPath = initLookupPath(request);
两种形式相比,次要是 initLookupPath 办法中多了 usesPathPatterns 选项,这是 Spring5 中的新玩意,所以明天松哥就通过一篇简略的文章来和大家分享一下 usesPathPatterns 到底是什么,该怎么玩!
这可不是一个小变动哦!特地是如果你在我的项目中应用了 WebFlux,那么这个货色就显得尤为重要了!
AntPathMatcher
当咱们应用 @RequestMapping 注解去标记申请接口的时候(或者应用它的相似办法如 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping),咱们能够应用一些通配符去匹配 URL 地址,举个简略例子,假如我有上面五个接口:
@GetMapping("/hello/**/hello")
public String hello() {return "/hello/**/hello";}
@GetMapping("/h?llo")
public String hello2() {return "/h?llo";}
@GetMapping("/**/*.html")
public String hello3() {return "/**/*.html";}
@GetMapping("/hello/{p1}/{p2}")
public String hello4(@PathVariable String p1, @PathVariable String p2) {System.out.println("p1 =" + p1);
System.out.println("p2 =" + p2);
return "/hello/{p1}/{p2}";
}
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {System.out.println("name =" + name);
System.out.println("version =" + version);
System.out.println("ext =" + ext);
}
在解释接口的含意之前,先来说说这几个通配符的含意:
通配符 | 含意 |
---|---|
** |
匹配 0 个或者多个目录 |
* |
匹配 0 个或者多个字符 |
? |
匹配任意单个字符 |
理解了通配符的含意,咱们再来说说各个接口都能接管哪些申请:
- 第一个接口,能够接管诸如
/hello/123/123/hello
、/hello/a/hello
以及/hello/hello
这样的申请,因为两头的**
代表 0 个或者多个目录。 - 第二个接口,能够接管诸如
/hallo
、/hello
、/hMllo
之类的申请,留神它不能接管/haallo
或者/hllo
,因为?
示意一个字符。 - 第三个接口能够接管任意以
.html
为后缀的申请,例如/aaa/bb/cc.html
、/aa.html
或者/aa/aa.html
。 - 第四个接口预计大家都比拟相熟,在 RESTful 格调的接口设计中预计大家都用过,它接管的申请格局相似于
/hello/aa/bb
,其中参数 p1 就对应 aa,参数 p2 对应 bb。 - 第五个接口则用到了正则,name、version 以及 ext 三个参数格局用正则表达出来,它能够接管诸如
/spring-web-3.0.5.jar
格局的申请,最终的参数 name 就是spring-web
,version 就是3.0.5
,ext 则是.jar
。
这是 SpringMVC 中之前就存在的性能,不论你用没用过,反正它统一存在。
那么是谁撑持了这个性能呢?那就是 AntPathMatcher。
AntPathMatcher 是一个实现了 Ant 格调的门路匹配器,Ant 格调的门路规定实际上就是咱们后面给大家介绍的那三种门路匹配符,很 Easy。这种门路匹配规定源自 Apache Ant 我的项目(https://ant.apache.org),Apache Ant 咱们当初其实曾经很少会用到了,它的替代品就是大家所熟知的 Maven,如果你有幸保护一些 2010 年之前的老我的项目的话,有可能会接触到 Ant。
AntPathMatcher 实际上在 SpringMVC 中有十分宽泛的利用,不仅仅是在 @RequestMapping 中定义接口用到,在其余一些波及到地址匹配的中央也会用到,例如咱们在 SpringMVC 的配置文件中配置动态资源过滤时,也是 Ant 格调门路匹配:
<mvc:resources mapping="/**" location="/"/>
另外像拦截器里的拦挡门路注册、跨域解决时的门路匹配等等,都会用到 Ant 格调的门路匹配符。
整体上来说,AntPathMatcher 是 Spring 中一种比拟原始的门路匹配解决方案,尽管比较简单,然而它的效率很低,并且在解决 URL 编码的时候也很不不便。
因而,才有了 Spring5 中的 PathPattern。
PathPattern
PathPattern 专为 Web 利用设计,它与之前的 AntPathMatcher 性能大部分比拟相似,当然也有一些轻微差别,这个松哥前面会说。
如果是 Servlet 利用,目前官网举荐的 URL 匹配解决方案就是 PathPattern(当然你也能够抉择较早的 AntPathMatcher),尽管官网举荐的是 PathPattern,但实际上默认应用的仍然是 AntPathMatcher;如果你用的是 WebFlux,PathPattern 就是惟一解决方案了。
留神,PathPattern 是一个十分陈腐的玩艺,目前 Spring 最新版是 5.3.4,在 Spring5.3 之前,咱们在 Servlet 利用中,也只能抉择 AntPathMatcher,从 Spring5.3 之后,咱们才能够应用 PathPattern 了。
PathPattern 会将 URL 规定预解析为 PathContainer,它对 URL 地址匹配的解决更加疾速,PathPattern 与 AntPathMatcher 的差别次要体现在两个方面:
第一,PathPattern 只反对结尾局部应用 **
,如果在门路的两头应用 **
就会报错,上文中第一个和第三个接口,在 PathPattern 模式下会报错,如下:
因为在两头或者开始应用 **
极易造成凌乱,因而 PathPattern 只反对在结尾应用 **
。
第二,PathPattern 反对应用诸如 {*path}
的形式进行门路匹配,这种写法也能够匹配到多层门路,并且将匹配到的值赋值给 path 变量,例如如下一个接口:
@GetMapping("/javaboy/{*path}")
public void hello6(@PathVariable String path) {System.out.println("path =" + path);
}
如果申请门路是 http://localhost:8080/javaboy/aa
,那么参数 path 的值就是 /aa
;
如果申请门路是 http://localhost:8080/javaboy/aa/bb/cc/dd
,那么参数 path 的值就是 /aa/bb/cc/dd
;
这个写法也比拟新鲜,因为之前的 AntPathMatcher 里边没有这个。
如何应用
默认状况下,SpringMVC 中应用的还是 AntPathMatcher,那么如何开启 PathPattern 呢?很简略,在 SpringBoot 我的项目中只须要增加如下配置即可:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {configurer.setPatternParser(new PathPatternParser());
}
}
增加了这个配置后,在咱们文章一开始贴出来的代码里,就会进入到 if 分支中,进而应用 PathPattern 去解析申请 URL。
小结
好啦,明天就和小伙伴们聊这么多,大家能够体验一把这个东东,不过留神抉择 Spring 的版本哦,肯定抉择 5.3 之上的版本~大家周末欢快哦~