让我们假设控制器的这两种情况会延迟生成一些随机数:
1) 反应式 Spring 5 反应式应用程序:
@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)传统的Spring MVC 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;
}
从 HTTP 客户端(浏览器、AJAX 请求)的角度来看,两种方案之间没有任何区别。我的意思是客户端将等到所有结果都发送完毕,并且在提交整个响应之前不会处理它们。
也就是说,尽管 spring web reactive 让我们认为它正在将结果发送回来,因为它们正在生成,但实际上它不会发生这种情况,并且客户端将无法处理结果,直到所有数字都有已生成。
使客户端完全响应的直接方法是使用 WebSockets。
那么,除了很酷的东西(比如漂亮的语义、组合......),考虑到浏览器 HTTP 请求不是响应式的并且等效于使用传统的 DeferredResult,使用 Spring Web Reactive 的意义何在?