反应式单声道如何将订阅上下文传播到"doOnSubscribe"和"doLast"



我有以下方面跟踪方法执行时间:

public Object addMetricsToReactiveMonoTimedMethod(ProceedingJoinPoint pjp, ReactiveTimed reactiveTimed) throws Throwable {
StopWatch stopWatch = new StopWatch();
Mono<?> mono = (Mono<?>) pjp.proceed();
return mono
.doOnSubscribe(subscription -> stopWatch.start())
.doFinally(signalType -> {
stopWatch.stop();
logTimer(pjp, stopWatch, reactiveTimed.name(), signalType);
});
}

方法本身如下所示:

public Mono<String> sayHi() { 
return Mono.just("hi")
.subscriberContext(context -> context.put("requestId", "requestId"));
}

如何在我的方面方法中从订阅者上下文中获取requestId变量?我想在doFinally中使用它来了解分析了哪个请求。

免责声明:我一生中从未使用过 Reactor 或类似的东西。由于aspectj标签,我发现了这个问题。

在快速浏览了 JavadocMono之后,看起来您可以在方面再次调用subscriberContext(Function<Context, Context>),就像在目标方法中一样。您可以获取现有上下文作为函数或 lambda 的输入参数,并且可以根据需要对其进行处理。虚拟函数/lambda 的结果将是一个新的上下文,但您可以丢弃它。我还没有测试过它,但我的意思是这样的:

// ...
Mono<?> mono = (Mono<?>) pjp.proceed();
// Alternatively, use a List<Context> with one element, a Stack<Context>, ...
Context[] targetContext = new Context[1];
mono.subscriberContext(context -> {
targetContext[0] = context;
// We can also return null, it does not matter because we are not interested
// in the newly created context, only in the original one we salvaged into the
// outer array.
return context;
});
System.out.println("Now do whatever you need to do with " + targetContext[0]);
// ...

我使用单元素数组/列表 - 相反,您可以"滥用"任何其他包装器对象,例如原子引用或线程本地作为包装器,因为您无法直接从 lambda 内部将 a 分配给Context变量。代码无法编译,因为从 lambda 内部引用的外部变量需要有效地成为最终变量。

最新更新