Web Reactive Programming - What are the advantages

2020-05-23 06:59发布

问题:

Lets suppose these two scenarios of a controller that generates some random numbers with a delay:

1) Reactive Spring 5 reactive application:

@GetMapping("/randomNumbers")
public Flux<Double> getReactiveRandomNumbers() {
    return generateRandomNumbers(10, 500);
}

/**
 * Non-blocking randon number generator
 * @param amount - # of numbers to generate
 * @param delay - delay between each number generation in milliseconds
 * @return
 */
public Flux<Double> generateRandomNumbers(int amount, int delay){
    return Flux.range(1, amount)
               .delayMillis(delay)
               .map(i -> Math.random());
}

2) Traditional Spring MVC with DeferredResult:

@GetMapping("/randomNumbers")
public DeferredResult<Double[]> getReactiveRandomNumbers() {
    DeferredResult<Double[]> dr = new DeferredResult<Double[]>();

    CompletableFuture.supplyAsync(() -> {
        return generateRandomNumbers(10, 500);
    }).whenCompleteAsync((p1, p2) -> {
        dr.setResult(p1);
    });

    return dr;
}

/**
 * Blocking randon number generator
 * @param amount - # of numbers to generate
 * @param delay - delay between each number generation in milliseconds
 * @return
 */
public Double[] generateRandomNumbers(int amount, int delay){
    int generated = 0;
    Double [] d = new Double[amount];
    while(generated < amount){
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {}
        d[generated] = Math.random();
        generated++;
    }
    return d;
}

From the perspective of a HTTP client (browser, AJAX request) there isn't any difference between both scenarios. I mean the client will wait until all the results are sent, and won't process them until the whole response is committed.

That is to say, although spring web reactive makes us think that it's sending the results back as they are being produced, in reality it doesn't happen that way and the client won't be able to process the results until all the numbers have been generated.

The straightforward way to make the client fully reactive would be to use WebSockets.

So, apart from the cool stuff (such as nice semantics, composition...), what is the point of using Spring Web Reactive considering that browser HTTP requests aren't reactive and are equivalent to using the traditional DeferredResult?

回答1:

There are differences so let me try to break it down.

For the DeferredResult<Double[]> return value clearly the array has to be prepared first before the value can be written to the response.

Spring Web Reactive does write each individual value from a Flux<Double> as it becomes available. Now from a browser perspective you may not see an actual difference because it won't give you the full JSON array until it's received in its entirety.

This is more a question of how to stream into a browser? For example if you add "Accept: text/event-stream" as a request header you can then consume each double as an individual event in the browser. So the capability of the server to do it and do it efficiently is there.