我们正在使用
Mono
来处理调用 REST 服务,我想通过添加一些额外的信息来增强异常处理,以便在必须抛出异常时使用。
粗略地说,我们的代码是这样的形式:
public ResultType callSomeService(Object param) {
return addTimeoutAndRetryToMono(getMonoForServiceCall(param)).block();
}
addTimeoutAndRetryToMono
是一个函数,它接受并返回 Mono
并添加超时、重试和错误映射。例如,它在错误映射中定义了我们抛出一个 TimeoutException
。
我想通过有关正在调用的服务的信息来增强
callSomeService
函数抛出的异常。例如,我想抛出一个自定义异常,并带有“调用 {some path} 时超时”之类的消息。
不幸的是,“路径”信息仅在
getMonoForServiceCall
中可用,它是基于OpenAPI规范生成的。
我将上面提到的功能简化为:
Mono<T> getMonoForServiceCall(Object param) {
....
// webClient comes from spring-webflux
// prepareRequest handles the http method, path, query params, etc., fairly boiler-plate stuff
...
WebClient.RequestBodySpec requestBuilder = prepareRequest(webClient, path, param);
return requestBuilder.retrieve().bodyToMono(returnType);
}
和
Mono<T> addTimeoutAndRetryToMono(Mono<T> mono) {
return mono.timeout(Duration.ofSeconds(10))
.onErrorMap(t -> handleExceptions(t));
}
Throwable handleExceptions(Throwable t) {
return new RestClientException("Here I would like to have the path of the API being called");
}
最简单的方法是传递“路径”信息,在
callSomeService
中捕获并抛出自定义异常,但是这些方法相当多,而且确实感觉“肮脏”。
我尝试在
contextWrite
中使用 getMonoForService
,将“路径”添加到上下文中,但我似乎无法在错误图中使用它。
理想的更改将在
getMonoForService
(我可以访问路径和其他相关字段)和addTimeoutAndRetryToMono
(添加错误映射)级别进行,因为它们位于共享库之一中并会产生更清洁的解决方案。 getMonoForServiceCall
函数应继续返回 Mono<T>
。
对于任何感兴趣的人,我设法解决了这个问题。
数据在
Mono
系统中流动的方式是,您在订阅 Mono
时(即调用 block
时)提供“上下文”。然后,上下文由 Mono
的各个层读取和处理,可能会影响最终结果。
我需要的是数据向后流动:底层,即进行实际 REST 调用的层,拥有我需要的
path
信息,并且我需要在调用 block
的方法中访问它。
当然,最简单的方法是让处理 REST 调用的层在组合对象中返回结果对象和路径。就我而言,这是不可接受的,因为这意味着破坏几个依赖库中的向后兼容性和代码更改。
为了使用
context
作为 path
数据的侧通道,我使用了“容器对象”。我使用 contextWrite
在上下文中添加此对象,在最终调用 block
的方法中。然后,在我可以访问“路径”的地方,我使用 deferContextual
来改变“容器对象”并存储路径。
一旦
block
方法完成,我就可以查看“容器对象”内部并检索路径。