我有一个反应性(Mono
)流,该流以多个步骤处理传入的数据。其中一些步骤收集Info
对象中的某种日志数据。该对象的实例通过Reactor的subscriberContext()
函数(请参见Project Reactor Docs)传递到这些处理步骤。在所有处理结束时,无论流是否成功,都必须保存Info对象。
我有一个示例实现:
import java.time.Instant;
import reactor.core.publisher.Mono;
public class CtxTest {
static class Info {
Instant timeStamp = Instant.now();
String input;
@Override
public String toString() {
return timeStamp.toString() + ": " + input;
}
}
public static void main(String... args) {
final String contextKey = "key";
Mono<String> mono = Mono.just("hello")
.flatMap(s -> Mono.subscriberContext()
.map(ctx -> transform(s, ctx.get(contextKey))))
.doAfterTerminate(() -> saveInfo(Mono.subscriberContext().block().get(contextKey))) // does not work
.subscriberContext(ctx -> ctx.put(contextKey, new Info()));
mono.subscribe(System.out::println);
}
static String transform(String input, Info info) {
info.input = input;
return input.toUpperCase();
}
static void saveInfo(Info info) {
System.out.println(info);
}
}
在这里,transform
是一个处理步骤,它转换输入的String并另外用日志记录数据填充Info
对象。我已验证.flatMap
步骤是否按预期进行。
但是,.doAfterTerminate
步骤给出了java.util.NoSuchElementException: Context is empty
异常。如何归档所需的行为?
旁注:
我发现了一些使用.doOnEach
访问上下文的示例。如果我将.doAfterTerminate
行替换为以下行:
.doOnEach(s -> saveInfo(s.getContext().get(contextKey)))
我成功地使用非空上下文对象调用了saveInfo
。有趣的是,一次运行main
会两次调用该函数。