Java 请求反应堆中的下一个';只有在需要的时候,它才会流动
我有一个API,它返回一个限制为100个实体的实体列表。如果有更多实体,它将返回下一页的令牌 我想创建一个通量,它返回(所有页面的)所有实体,但仅在需要时(如果请求的话)返回 我写了这段代码:Java 请求反应堆中的下一个';只有在需要的时候,它才会流动,java,spring,spring-webflux,project-reactor,Java,Spring,Spring Webflux,Project Reactor,我有一个API,它返回一个限制为100个实体的实体列表。如果有更多实体,它将返回下一页的令牌 我想创建一个通量,它返回(所有页面的)所有实体,但仅在需要时(如果请求的话)返回 我写了这段代码: class Page { String token; List<Object> entities; } Flux<Object> load(String token, final Function<String, Mono<Page>> f
class Page {
String token;
List<Object> entities;
}
Flux<Object> load(String token, final Function<String, Mono<Page>> fct) {
return fct.apply(token).flatMapMany(page -> {
if (page.token == null) {
// no more pages
return Flux.fromIterable(page.entities);
}
return Flux.fromIterable(page.entities).concatWith(Flux.defer(() -> load(page.token, fct)));
});
}
预期为:在最后一个请求(1)之后加载第2页
这几乎像是在某个地方有预取,但我看不到在哪里。有什么想法吗?好的,我找到了。没有预先回迁。实际上是
Flux.defer
在订阅时加载下一页,而不是在请求时加载
一个快速(且不干净)的测试修复了以下问题:
Flux<Object> load(String token, final Function<String, Mono<Page>> fct) {
return fct.apply(token).flatMapMany(page -> {
if (page.token == null) {
// no more pages
return Flux.fromIterable(page.entities);
}
return Flux
.fromIterable(page.entities)
.concatWith(
// Flux.defer(() -> load(page.token, fct))
Flux.create(s -> {
DelegateSubscriber[] ref = new DelegateSubscriber[1];
s.onRequest(l -> {
if (ref[0] == null) {
ref[0] = new DelegateSubscriber(s);
load(page.token, fct).subscribe(ref[0]);
}
ref[0].request(l);
});
}));
});
}
static class DelegateSubscriber extends BaseSubscriber<Object> {
FluxSink<Object> delegate;
public DelegateSubscriber(final FluxSink<Object> delegate) {
this.delegate = delegate;
}
@Override
protected void hookOnSubscribe(Subscription subscription) {
// nothing
}
@Override
protected void hookOnNext(Object value) {
delegate.next(value);
}
@Override
protected void hookOnError(Throwable throwable) {
delegate.error(throwable);
}
}
通量加载(字符串标记,最终函数fct){
返回fct.apply(令牌).flatMapMany(第->{
如果(page.token==null){
//没有更多的页面
返回通量.fromIterable(第页实体);
}
回流通量
.fromIterable(第页实体)
康卡特维思先生(
//流量延迟(()->加载(page.token,fct))
通量。创建(s->{
DelegateSubscriber[]ref=新的DelegateSubscriber[1];
s、 onRequest(l->{
if(ref[0]==null){
ref[0]=新的被委派订户;
加载(page.token,fct).订阅(ref[0]);
}
参考[0]。请求(l);
});
}));
});
}
静态类DelegateSubscriber扩展BaseSubscriber{
FluxSink代表;
公共委托订户(最终FluxSink委托){
this.delegate=委托;
}
@凌驾
受保护的void hookonsubscripte(订阅){
//没什么
}
@凌驾
受保护的void hookOnNext(对象值){
下一步(值);
}
@凌驾
受保护的空挂钩器(可丢弃){
委托错误(可丢弃);
}
}
您可以执行以下操作:从适配器创建一个流量,该流量将在内部订阅第一页和缓冲区元素。当不需要发出更多元素且存在下一页时,适配器将创建对下一页的新订阅
Flux<Object> load(String token, final Function<String, Mono<Page>> fct) {
return fct.apply(token).flatMapMany(page -> {
if (page.token == null) {
// no more pages
return Flux.fromIterable(page.entities);
}
return Flux
.fromIterable(page.entities)
.concatWith(
// Flux.defer(() -> load(page.token, fct))
Flux.create(s -> {
DelegateSubscriber[] ref = new DelegateSubscriber[1];
s.onRequest(l -> {
if (ref[0] == null) {
ref[0] = new DelegateSubscriber(s);
load(page.token, fct).subscribe(ref[0]);
}
ref[0].request(l);
});
}));
});
}
static class DelegateSubscriber extends BaseSubscriber<Object> {
FluxSink<Object> delegate;
public DelegateSubscriber(final FluxSink<Object> delegate) {
this.delegate = delegate;
}
@Override
protected void hookOnSubscribe(Subscription subscription) {
// nothing
}
@Override
protected void hookOnNext(Object value) {
delegate.next(value);
}
@Override
protected void hookOnError(Throwable throwable) {
delegate.error(throwable);
}
}