异常向北,流转向南(IF-ELSE 清除计划续)

上一篇,
IF-ELSE
清除计划之管道风
,诸位老哥看了我一顿乱扯,一锅乱炖,就像我上篇总结的一样,我其实是描述了 IF-ELSE
清除计划的前置条件,具有管道的意识,然后我们继续执行清除计划,这篇我们着重谈谈怎么通过 Optional
Function
实现管道的短路和流转

切题

异常向北(上),流转向南(下)!如上篇所述,管道模式是有 Valve
阀门
)和 Status
状态
)的,这两个组件主要是控制代码的流转,也就是真实用来清理 IF-ELSE
的实现,但是我们 CRUD-BOYS
使用的是极简模式的管道,并没有加入这些组件,那我们处理 IF-ELSE
其实是通过以下几种方式

  • 阀门管道(执行断路逻辑)以及通路管道(空值逻辑传递)
  • 异常管道抛出异常使得执行向北,其实就是向上层抛出异常(抛给外部异常捕获框架)
  • 正常逻辑走其他分支管道,流转向南,继续往下执行

来源

Optional

Java8
的新特性终于让我们可以使用函数式编程了,同时也提供了很多非常优秀的工具,比如我们今天的主角 Optional
,他是用于进行控制判断的工具,很多文章都是这么说的。。。但是如果你仔细看看它的 api
,你会发现它其实一点也不简单,让我们看看今天会使用的几个方法

//用于过滤,可以有效清理`IF-ELSE`
public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

//用于装载极简管道,注意其实可以使用andThen多级连接
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            //这里返回的还是Optional
            return Optional.ofNullable(mapper.apply(value));
        }
    }
复制代码

Function

//嘿嘿,炒一份冷饭,就是极简管道的核心方法
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
复制代码

搞起

为了方便大家理解,我们使用一个稍微复杂场景来进行举例,同时也是为了方便大家能够在实际的业务中使用,减少 知行合一
的成本,更好的方便实践,这个场景就是使用 JWT
进行权限校验, Token
存放在请求头中,然后校验 Token
的有效性,获取用户的信息,接着获取用户的权限,校验当前 Url
是否在用户的权限中,我们试试校验Token有效性

public static void main(String[] args) {
        HttpServletRequest request = new HttpServletRequestWrapper(null);
        //如果不拼接极简管道,会有大量的`IF-ELSE`出现
        //而且这边的逻辑本质就是校验Token是否有效
        String headerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
        //流转逻辑一直->向南
        String userId = Optional.ofNullable(headerToken)
            	//分支管道,干掉IF-ELSE
                .filter(StringUtils::isNoneBlank)
                //极简管道拼接
                .map(parseUserIdFromToken().andThen(gainCacheFromRedis()))
                //这个比较其实是防止Token泄露等异常情况
                .filter(cacheToken -> StringUtils.equals(headerToken, cacheToken))
                //校验完成后,再获取一次UserId
                //其实可以在上一个Map直接封装一层,这边只做演示,不做复杂拓展
                .map(parseUserIdFromToken())
                //所有的逻辑都由该异常->向北  这是异常管道
                .orElseThrow(() -> new RuntimeException("Token异常!"));
        //todo 继续通过UserId获取用户权限
    }
    
/**
 * 模拟JWT解析
 *
 * @return 从Token中解析UserId
 */
private static Function<String, String> parseUserIdFromToken() {
        return token -> "JWT解析UserId";
    }

/**
 * 模拟Redis获取缓存分布式缓存简单实现)
 *
 * @return 从Redis中获取UserId对应的Token
 */
private static Function<String, String> gainCacheFromRedis() {
        return userId -> "通过Redis获取到的Token";
    }
复制代码

真心小结

当我把上篇文章发到某个神秘的技术群时,有大佬一针见血的指出了这种方式其实也是 IF-ELSE
,本质上也是条件判断,在重新审视代码和逻辑后发现确实如此,但是我依然要指出这样处理 IF-ELSE
的好处,即管道之间的 IF-ELSE
逻辑是隔离的,校验 Token
有效性的管道部分和通过 UserId
获取用户权限的管道之间的条件判断是隔离的,而不是堆在一起形成一段又一段的 IF-ELSE
代码块,当然,这只是一家之言,也只是初步思考以后的实现,肯定会有疏漏,初衷也是期望对大家有所帮助,也希望有大佬可以提出更优美的解法,造福我等 CRUD-BOY
,最后谢谢您的阅读,祝端午安康,阖家幸福

咸鸭蛋(彩蛋的一种)

最近其实有机会接触并使用了 Spring Webflux
实现的 Spring Cloud Gateway
,这是 Spring
基于 Reactor
响应式编程实现,在 Spring Webflux
的场景中,所有的处理结果在 subscribe
之前都是不可直接读取,因为 subscribe
是会 block
当前线程的,这在响应式编程之中是不允许的,所以在 Reactor
数据流转就是流式的, IF-ELSE
可以控制到出现得很少,而所有的数据必须被 Mono
Flux
包裹,而 Mono
Flux
api
是管道模式的大成者,可以做到一段到底,绝不分割,下面贴出 Spring Webflux
一个小例子,大家可以尝试借鉴一哈

String hello = Mono
        .just("HelloWorld")
        //可以直接进行判断
        .switchIfEmpty(Mono.just("HelloReactor"))
        //可以设置默认值
        .defaultIfEmpty("MyMan")
        //可以转换其他值
        .flatMap(word -> Mono.defer(() -> Mono.just("HelloPipeline")))
        //延迟操作
        .doOnSuccess(System.out::println)
        .doOnError(System.out::println)
        .block();
System.out.println(hello);
复制代码

原文 

https://juejin.im/post/5ef702c9e51d45349e2540e7

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 异常向北,流转向南(IF-ELSE 清除计划续)

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址