Java 8 默认方法实践
Spring Boot 2.4.x已经用了一年多,借着新业务调整的时机把依赖升级到最新的Spring Boot 2.6.5,在升级的时候遇到一个优化点,非常有意思,我觉得值得拿出来分享一下。
public interface Checker {
boolean check(Authentication authentication, HttpServletRequest request);
Predicate<HttpServletRequest> whitePredicate();
}
上面接口是用来做动态权限的,它包含了两个方法
check
用来检测当前请求是否和当前认证信息一致whitePredicate
是开放的一个白名单断言,方便放行一些请求的。
最开始whitePredicate
因为业务有白名单配置,因此没什么问题,都感觉这个接口设计很好。但是推广到其它项目的时候就不太优雅了,不是所有的业务都有白名单接口,无奈就给个白名单实现:
public Predicate<HttpServletRequest> whitePredicate() {
// false 表示没白名单
return request -> false;
}
false
表示没白名单。
后面升级的过程中,就把没把白名单作为一种默认的情况抽象了出来,使用了Java 8出现的接口默认方法。这样自然Checker
就成为了函数式接口:
@FunctionalInterface
public interface Checker {
boolean check(Authentication authentication, HttpServletRequest request);
default Predicate<HttpServletRequest> whitePredicate() {
return request -> false;
}
}
但是这里还有一个痛点,每次实现check
都要通过whitePredicate
对请求访问进行白名单断言:
public boolean check(Authentication authentication, HttpServletRequest request) {
// 白名单断言
if (whitePredicate().test(request)) {
return true;
}
// 处理逻辑
}
非常不方便,而且whitePredicate
方法并没体现在设计意图中,因此又进行了抽象,把流程固化:
@FunctionalInterface
public interface Checker {
default boolean check(Authentication authentication, HttpServletRequest request) {
if (whitePredicate().test(request)) {
return true;
}
return doCheck(authentication, request);
}
boolean doCheck(Authentication authentication, HttpServletRequest request);
default Predicate<HttpServletRequest> whitePredicate() {
return request -> false;
}
}
这样check
的流程就被固化下来,白名单方法一定会先执行,剩下的检测委托给doCheck
方法来处理。这样设计更加合理紧凑。而且保证了Checker
还是一个函数式接口,Java 8 默认方法的意义应该就在这里。或许一开始就应该这样处理,只不过当时没考虑到去固化流程。
从这里可以看得出,其实好的设计并不是开始就有的,经过一次次的迭代和优化、抽象归纳才会有现在的样子。另外也需要结合一些新技术、新特性。有时候不是你集成集成了新技术就是新技术,只有用了新技术才是新技术。你对此有什么看法?欢迎留言讨论。
评论系统未开启,无法评论!