有没有办法更新Reactor 3中的上下文?

时间:2017-12-13 14:44:02

标签: java project-reactor

根据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

2 个答案:

答案 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();
    }
}