如何在不阻塞的情况下在空 Mono 之后链接反应操作?
How to chain reactive operations after empty Mono without blocking?
基本上我想要实现的是调用第二个存储库(ReactiveCrudRepository
)或抛出异常,具体取决于调用第一个存储库的结果。
我最初的想法是这样的:
/** Reactive with blocking code */
public Flux<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
// Warning: "Inappropriate blocking method call"
.blockOptional() // this fails in test-context
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
这将对应于以下非反应性方法:
/** Non-reactive */
public List<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
我还没有找到以反应性非阻塞方式执行此操作的方法。如果第一次调用出现空 Mono
,我需要的只是抛出一个错误,如果不为空则继续管道;但我似乎无法在这里正确使用 onErrorStop
或 doOnError
,并且 map
没有帮助,因为它跳过空的 Mono
.
如果我使用 id
而不是 name
,我有一个解决方法,但我对它不太满意,因为它在实例的情况下表现出不同的行为FirstThing
但没有 SecondThing
链接到它:
/** Reactive workaround 1 */
public Flux<SecondThing> getThings(Long firstThingId) {
return secondRepo
.findAllByFirstThingId(firstThingId)
.switchIfEmpty(
Flux.error(() -> new FirstThingNotFound(firstThingName))
);
}
我发现的另一种解决方法如下,它将空 Mono
替换为 null
值,但它看起来不正确并且也会引发警告:
/** Reactive workaround 2 */
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
// Warning: "Passing 'null' argument to parameter annotated as @NotNull"
.defaultIfEmpty(null)
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
)
.onErrorMap(
NullPointerException.class, e -> new FirstThingNotFound(firstThingName)
);
}
什么是将调用链接到两个存储库的正确方法,以便 FirstThing
的存在或不存在与所请求的 firstThingName
条件调用第二个 repo?
我找到了一个非常简单的解决方案,我可能会因为没有早点找到它而感到羞愧:
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
.switchIfEmpty(Mono.error(() -> new FirstThingNotFound(firstThingName)))
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
);
}
诀窍在于 switchIfEmpty
不会强制您选择“有效”替换值,因此可以使用 Mono.error
直接传播正确的异常。
基本上我想要实现的是调用第二个存储库(ReactiveCrudRepository
)或抛出异常,具体取决于调用第一个存储库的结果。
我最初的想法是这样的:
/** Reactive with blocking code */
public Flux<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
// Warning: "Inappropriate blocking method call"
.blockOptional() // this fails in test-context
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
这将对应于以下非反应性方法:
/** Non-reactive */
public List<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
我还没有找到以反应性非阻塞方式执行此操作的方法。如果第一次调用出现空 Mono
,我需要的只是抛出一个错误,如果不为空则继续管道;但我似乎无法在这里正确使用 onErrorStop
或 doOnError
,并且 map
没有帮助,因为它跳过空的 Mono
.
如果我使用 id
而不是 name
,我有一个解决方法,但我对它不太满意,因为它在实例的情况下表现出不同的行为FirstThing
但没有 SecondThing
链接到它:
/** Reactive workaround 1 */
public Flux<SecondThing> getThings(Long firstThingId) {
return secondRepo
.findAllByFirstThingId(firstThingId)
.switchIfEmpty(
Flux.error(() -> new FirstThingNotFound(firstThingName))
);
}
我发现的另一种解决方法如下,它将空 Mono
替换为 null
值,但它看起来不正确并且也会引发警告:
/** Reactive workaround 2 */
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
// Warning: "Passing 'null' argument to parameter annotated as @NotNull"
.defaultIfEmpty(null)
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
)
.onErrorMap(
NullPointerException.class, e -> new FirstThingNotFound(firstThingName)
);
}
什么是将调用链接到两个存储库的正确方法,以便 FirstThing
的存在或不存在与所请求的 firstThingName
条件调用第二个 repo?
我找到了一个非常简单的解决方案,我可能会因为没有早点找到它而感到羞愧:
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
.switchIfEmpty(Mono.error(() -> new FirstThingNotFound(firstThingName)))
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
);
}
诀窍在于 switchIfEmpty
不会强制您选择“有效”替换值,因此可以使用 Mono.error
直接传播正确的异常。