根据reference guide,添加到反应序列的上下文是不可变的:
使用put(对象键,对象值)存储键值对,返回 一个新的Context实例。
然后我想知道是否存在某种“解决方法”以更新序列的上下文,例如替换旧序列。
为了说明我的情况,请考虑以下示例:
@Test
public void contextGlobalTest() {
Flux<String> chars = Flux.fromIterable(Arrays.asList("a", "b", "c", "d"));
chars.flatMap(this::concat)
.flatMap(m -> Mono.subscriberContext().map(ctx -> m + ctx.get("key2")))
.subscriberContext(Context.of("key1", 1, "key2", "yy"))
.subscribe(System.out::println);
}
private Flux<String> concat(String s) {
Flux<String> flux = Flux.just(s + s);
return flux.flatMap(entry -> Mono.subscriberContext()
.map(ctx -> entry + ctx.get("key1")))
.subscriberContext(Context.of("key1", 2, "key2", "zz"));
}
输出是: aa2yy bb2yy cc2yy dd2yy, 但我在期待: aa2zz bb2zz cc2zz dd2zz
这种情况有解决方法吗?
对于那些感兴趣的人,我想出了一个解决方法: 需要为上下文提供一个可变对象,然后在上下文中改变该对象的属性。 有关详细信息,请参阅that post
答案 0 :(得分:1)
Sinks(SynchronousSink,MonoSink,FluxSink)和CoreSubscriber可以访问currentContext,但这些选项并不总是可用。
答案 1 :(得分:1)
由于上下文是不可变的,因此每次都要检索一个新的上下文,因此在'concat'中,可见上下文(key1 = 2)仅在该flatmap中,一旦它离开并移到flatmap的外部,只有key1 = 1上下文可见。 如果你真的想要更新上下文,那么可能会使上下文像
一样可变@Test
public void contextGlobalTest() {
MutableContext mutableContext = new MutableContext();
Flux.fromIterable(Arrays.asList("a", "b", "c", "d"))
.flatMap(s -> Flux.just(s + s)
.flatMap(entry -> Mono.subscriberContext()
.map(ctx -> entry + ctx.get("key1")))
.subscriberContext(ctx -> mutableContext.put("key1", 2).put("key2", "zz")))
.flatMap(m -> Mono.subscriberContext().map(ctx -> m + ctx.get("key2")))
.subscriberContext(ctx -> mutableContext.put("key1", 1).put("key2", "yy"))
.subscribe(System.out::println);
}
static class MutableContext implements Context {
HashMap<Object, Object> holder = new HashMap<>();
@Override
public <T> T get(Object key) {
return (T) holder.get(key);
}
@Override
public boolean hasKey(Object key) {
return holder.containsKey(key);
}
@Override
public Context put(Object key, Object value) {
holder.put(key, value);
return this;
}
@Override
public Context delete(Object key) {
holder.remove(key);
return this;
}
@Override
public Stream<Map.Entry<Object, Object>> stream() {
return holder.entrySet().stream();
}
}