Java ExchangeFilterFunction是否在WebClient反应流外部执行代码?
我正在为Java ExchangeFilterFunction是否在WebClient反应流外部执行代码?,java,spring,spring-webflux,spring-webclient,Java,Spring,Spring Webflux,Spring Webclient,我正在为WebClient请求期间的扩展日志创建ExchangeFilterFunction 问题:在下面的示例中,如果在.doOnNext()函数中执行日志记录,会有什么区别吗?或者他们在处理上是平等的 ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { LOGGER.info("Request url=" + clientResponse.url() + ", method=" + clientRespons
WebClient
请求期间的扩展日志创建ExchangeFilterFunction
问题:在下面的示例中,如果在.doOnNext()
函数中执行日志记录,会有什么区别吗?或者他们在处理上是平等的
ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
LOGGER.info("Request url=" + clientResponse.url() + ", method=" + clientResponse.method());
return Mono.just(clientRequest);
});
ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
return Mono.just(clientRequest).doOnNext(clientResponse2 -> {
LOGGER.info("Request url=" + clientResponse2.url() + ", method=" + clientResponse2.method());
});
});
一个比另一个有什么优势吗?我只是不愿意在你的流程中人为地引入
Mono。只是或类似的东西。我认为.doOnNext
是一个额外的步骤,但我无法想象它会有什么不同。最好避免中断流程。我认为那将是你表现最差的点球
注意:如下所述,当调用WebClient
时,这会记录下来,通常看起来比使用方便的方法更难看,但它避免使用Mono.just
@Override
public void run(ApplicationArguments args) throws Exception {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:8080/")
.filter(eff)
.build();
webClient.get().retrieve().bodyToMono(String.class).subscribe(System.out::println);
}
ExchangeFilterFunction eff = (cr,ef)->{
System.out.println("method: " + cr.method());
return ef.exchange(cr)
.map(cresp->{
System.out.println(cresp.rawStatusCode());
return cresp;
});
};
在这种特殊情况下,webclient将正确调用过滤器。但是,总体上要注意这一点
在第一种情况下,当调用方法时将发生日志记录。如果调用方从未订阅返回的发布服务器,则实际上可能是不正确的。发布者也可能被多次调用,比如在重试或重复等情况下,这也将是错误的
在第二种情况下,它将在每次订阅时调用
public class Foo {
static Mono<String> echo(String message) {
System.out.println("echo called with " + message);
return Mono.just(message);
}
static Mono<String> rxEcho(String message) {
return Mono.just(message).doOnNext(msg -> System.out.println("rxEcho was called with " + msg));
}
public static void main(String[] args) {
//logged, even though never actually called
echo("no sub");
//only logs 1 time
echo("retry")
.repeat(3)
.blockLast();
System.out.println("---------------");
//never subbed, never logged
rxEcho("no sub");
//all 4 calls are logged
rxEcho("retry")
.repeat(3)
.blockLast();
}
}
公共类Foo{
静态单声道回波(字符串消息){
System.out.println(“用“+消息调用的echo”);
返回Mono.just(消息);
}
静态单声道rxEcho(字符串消息){
返回Mono.just(message.doOnNext(msg->System.out.println(“用“+msg”调用rxEcho));
}
公共静态void main(字符串[]args){
//已登录,即使从未实际调用
echo(“无子公司”);
//只记录1次
回显(“重试”)
.重复(3)
.blockLast();
System.out.println(“--------------”;
//从不下床,从不记录
rxEcho(“无子公司”);
//所有4个电话都记录在案
rxEcho(“重试”)
.重复(3)
.blockLast();
}
}
还要注意的是,在实际代码中不应该调用任何block()风格,我不想将示例与StepVerifier混淆。但是,在webclient调用中添加显式日志作为步骤是我试图避免的。我宁愿使用全局记录器一次性配置webclient,然后在任何webcall上都不必关心日志记录,因为它是自动应用的。类似于restemplate
s如何配置用于日志记录的拦截器。您认为您的代码在做什么?进一步阅读baeldung的文章,你会看到许多其他的可能性。然后还有其他的可能性。实际上有区别,请看我的答案。这很好,但离题了。我认为如果没有订阅,网络客户端根本不会被调用。你错了。它很可能在.switchIfEmpty()中调用,但从未订阅,因为另一个发布服务器发出一个值。我总是这样做。关键是你不(也不应该)知道出版商是如何使用的。您需要在订阅上执行操作,而不是调用。