(15)Reactor 3 Operators——響應式Spring的道法術器

本系列文章索引《響應式Spring的道法術器》
前情提要 Reactor 3快速上手 | 響應式流規範java

2.5 Reactor 3 Operators

雖然響應式流規範中對Operator(如下均稱做」操做符「)並未作要求,可是與RxJava等響應式開發庫同樣,Reactor也提供了很是豐富的操做符。react

2.5.1 豐富的操做符

本系列前邊的文章中,陸續介紹了一些經常使用的操做符。但那也只是冰山之一角,Reactor 3提供了豐富的操做符,若是要一個一個介紹,那篇幅大了去了,授人以魚不如授人以漁,咱們能夠經過如下幾種途徑瞭解操做符的應用場景,熟悉它們的使用方法:git

  1. 附2是《Reactor 3 參考文檔》中關於「如何選擇合適的操做符」一節的翻譯,介紹瞭如何選擇合適的操做符。
  2. 參考Javadoc中對Flux和Mono的解釋和示意圖。
  3. 若是想經過實戰的方式上手試一下各類操做符,強烈推薦來自Reactor官方的lite-rx-api-hands-on項目。拿到項目後,你要作的就是使用操做符,完成「TODO」的代碼,讓全部的@Test綠燈就OK了。相信完成這些測試以後,對於常見的操做符就能瞭然於胸了。
  4. 此外,在平常的開發過程當中,經過IDE也能夠隨時查閱,好比IntelliJ:

title

因爲Project Reactor的核心開發團隊也有來自RxJava的大牛,而且Reactor自己在開發過程當中也借鑑了大多數RxJava的操做符命名(對於RxJava中少許命名不夠清晰的操做符進行了優化),所以對於熟悉RxJava的朋友來講,使用Reactor基本沒有學習成本。一樣的,學習了Reactor以後,再去使用RxJava也沒有問題。github

2.5.2 「打包」操做符

咱們在開發過程當中,爲了保持代碼的簡潔,一般會將常常使用的一系列操做封裝到方法中,以備調用。api

Reactor也提供了相似的對操做符的「打包」方法。ide

1)使用 transform 操做符函數

transform能夠將一段操做鏈打包爲一個函數式。這個函數式能在組裝期將被封裝的操做符還原並接入到調用transform的位置。這樣作和直接將被封裝的操做符加入到鏈上的效果是同樣的。示例以下:學習

@Test
    public void testTransform() {
        Function<Flux<String>, Flux<String>> filterAndMap =
                f -> f.filter(color -> !color.equals("orange"))
                        .map(String::toUpperCase);

        Flux.fromIterable(Arrays.asList("blue", "green", "orange", "purple"))
                .doOnNext(System.out::println)
                .transform(filterAndMap)
                .subscribe(d -> System.out.println("Subscriber to Transformed MapAndFilter: "+d));
    }

這個例子,經過名爲filterAndMap的函數式將filtermap操做符進行了打包,而後交給transform拼裝到操做鏈中。輸出以下:測試

blue
Subscriber to Transformed MapAndFilter: BLUE
green
Subscriber to Transformed MapAndFilter: GREEN
orange
purple
Subscriber to Transformed MapAndFilter: PURPLE

2)使用 compose 操做符優化

compose 操做符與 transform 相似,也可以將幾個操做符封裝到一個函數式中。主要的區別就是,這個函數式是針對每個訂閱者起做用的。這意味着它對每個 subscription 能夠生成不一樣的操做鏈。舉個例子:

public void testCompose() {
        AtomicInteger ai = new AtomicInteger();
        Function<Flux<String>, Flux<String>> filterAndMap = f -> {
            if (ai.incrementAndGet() == 1) {
                return f.filter(color -> !color.equals("orange"))
                        .map(String::toUpperCase);
            }
            return f.filter(color -> !color.equals("purple"))
                    .map(String::toUpperCase);
        };

        Flux<String> composedFlux =
                Flux.fromIterable(Arrays.asList("blue", "green", "orange", "purple"))
                        .doOnNext(System.out::println)
                        .compose(filterAndMap);

        composedFlux.subscribe(d -> System.out.println("Subscriber 1 to Composed MapAndFilter :" + d));
        composedFlux.subscribe(d -> System.out.println("Subscriber 2 to Composed MapAndFilter: " + d));
    }

這個例子中,filterAndMap函數式有一個名爲ai的會自增的狀態值。每次調用subscribe方法進行訂閱的時候,compose會致使ai自增,從而兩次訂閱的操做鏈是不一樣的。輸出以下:

blue
Subscriber 1 to Composed MapAndFilter :BLUE
green
Subscriber 1 to Composed MapAndFilter :GREEN
orange
purple
Subscriber 1 to Composed MapAndFilter :PURPLE
blue
Subscriber 2 to Composed MapAndFilter: BLUE
green
Subscriber 2 to Composed MapAndFilter: GREEN
orange
Subscriber 2 to Composed MapAndFilter: ORANGE
purple

也就是說,compose中打包的函數式能夠是有狀態的(stateful):

title

transform打包的函數式是無狀態的。將compose換成transform再次執行,發現兩次訂閱的操做鏈是同樣的,都會過濾掉orange

title

相關文章
相關標籤/搜索