springboot webflux响应式编程再探

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

有同学问我什么是响应式编程,

专业的解释是: 响应式编程(reactive programming)是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式。 那数据流(data stream)和声明式(declarative)怎么理解呢?那就要提一提我们的Stream流了。

Stream流的使用分为三个步骤(创建Stream流、执行中间操作、执行最终操作)。

stream的中间操作Intermediate:打开流做一定的数据过滤和映射,得到一个新的流。 filter过滤

map 处理

mapToInt 转int

flatMap 降维

peek 遍历操作是一个中间操作

skip 跳过多少元素skip(6)

limit裁剪操作limit(6)取前六个元素

sorted排序,默认从小到大排序,sorted() sorted(Comparator<? super T> comparator)

distinct去重。

stream的终止操作:Terminal:终结操作,一个流只能有一个terminal操作,当这个操作执行后,流就被使用"光"了,无法再被操作。所以这必定是流的最后一个操作。 Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。 f

orEach forEachOrdered

toArray返回一个Object[] toArray(Student[]::new);

reduce 归纳操作 需要提供一个起始值,根据一定的规则进行运算

collect .collect(Collectors.toList()); .collect(Collectors.toCollection(TreeSet::new)); List转map: .collect(Collectors.toMap(Student::getAge,s->s));

max/min 找出最大/最小的元素。max/min必须传入一个Comparator

count 返回元素数量

短路终止: anyMatch 任意匹配; allMatch 所有匹配; noneMatch 没有匹配; findFirst 返回第一个元素; findAny 返回任意一个元素。

说了这么多,怎么理解数据流和声明式呢? 本来数据是我们自行处理的,后来我们把要处理的数据抽象出来(变成了数据流),然后通过API去处理数据流中的数据(是声明式的)

比如下面的代码;将数组中的数据变成数据流,通过显式声明调用.sum()来处理数据流中的数据,得到最终的结果:

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).parallel().sum();
    System.out.println("结果为:" + sum2);
}
复制代码

说了这么多,今天来看看webflux实现websocket的功能。

WebFlux 本身提供了对 WebSocket 协议的支持,处理 WebSocket 请求需要对应的 handler 实现 WebSocketHandler 接口,每一个 WebSocket 都有一个关联的 WebSocketSession,包含了建立请求时的握手信息 HandshakeInfo,以及其它相关的信息。可以通过 session 的 receive() 方法来接收客户端的数据,通过 session 的 send() 方法向客户端发送数据。

直接上代码:

第一步 配置websocket

@Configuration
public class WebSocketConfig {

    @Bean
    public HandlerMapping handlerMapping(@Autowired EchoHandler echoHandler){
        //定义映射集合
        Map<String, WebSocketHandler> map = new HashMap<>();
        //配置映射模型
        map.put("/websocket/{token}", echoHandler);
        //映射处理
        SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
        //优先配置
        handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
        //映射路劲
        handlerMapping.setUrlMap(map);
        return handlerMapping;//
    }

    //配置适配器
    @Bean
    public WebSocketHandlerAdapter webSocketHandlerAdapter(){
        return new WebSocketHandlerAdapter();

    }
}
复制代码

第二步 开发webSocketHandler

@Component
@Slf4j
public class EchoHandler implements WebSocketHandler {

    //websocket处理终端
    @Override
    public Mono<Void> handle(WebSocketSession session) {
        log.info("websocket的握手信息={}", session.getHandshakeInfo().getUri());
        return session.send(session.receive().map(msg->session.textMessage("[Echo]"+msg.getPayloadAsText())));
    }
}
复制代码

第三步 websocket测试

www.jsons.cn/websocket/ 网站上输入:ws://localhost:8089/websocket/test 点击WebSocket连接,输入消息,控制台打印消息如下:

连接成功,现在你可以发送信息进行测试了!

你发送的信息 2021-11-17 17:08:45
hello

服务端回应 2021-11-17 17:08:45
[Echo]hello

你发送的信息 2021-11-17 17:08:54
你好呀

服务端回应 2021-11-17 17:08:54
[Echo]你好呀

这样就能够发/websocket/{msg} 的 WebSocket 请求交给 EchoHandler 处理。 还要为 WebSocket 类型的 handler 创建对应的 WebSocketHandlerAdapter,以便让 DispatcherHandler 能够调用我们的 WebSocketHandler。 完成这三个步骤后,当一个 WebSocket 请求到达 WebFlux 时,首先由 DispatcherHandler 进行处理,它会根据已有的 HandlerMapping 找到这个 WebSocket 请求对应的 handler,接着发现该 handler 实现了 WebSocketHandler 接口,于是会通过 WebSocketHandlerAdapter 来完成该 handler 的调用。

很明显这样的操作是有问题的。WebSocket 是全双工通信,如何实现双向通信,而不是一次请求一次返回,这样没有任何的的实际意义,另外SimpleUrlHandlerMapping的URL配置映射模型也是国定的,添加新的Handler则需要修改配置,很麻烦。那么该如何优化呢?

且在下回分解。

猜你喜欢

转载自juejin.im/post/7031504769382514724