尝试缓存Mono
返回的WebClient
时遇到问题。代码是这样的:
public Mono<Token> authenticate() {
return cachedTokenMono = cachedTokenMono
.switchIfEmpty(
Mono.defer(() ->
getToken())
.cache(token ->
Duration.between(Instant.now(), token.getExpires().toInstant()),
(Throwable throwable) -> Duration.ZERO,
() -> Duration.ZERO));
}
目的是缓存用于接收Mono
的{{1}},直到令牌过期为止。令牌过期后,缓存的Token
将变为空,并请求一个新令牌。
这可以按预期工作,但不幸的是Mono
实际上并没有“切换”,而是包装了源switchIfEmpty()
。结果,随着创建越来越多的包装Mono
,这会导致内存泄漏。
在这种情况下正确的模式是什么?有没有办法用新的SwitchIfEmptyMono
代替空的{1>}?
答案 0 :(得分:2)
您可以执行以下操作:
private final Mono<Token> authenticateMono = getToken()
.cache(
token -> Duration.between(Instant.now(), token.getExpires().toInstant()),
throwable -> Duration.ZERO,
() -> Duration.ZERO)
public Mono<Token> authenticate() {
return authenticateMono;
}
这个想法是,您对Mono<Token>
的每次调用都返回相同的缓存authenticate()
实例。 .cache
运算符确保为每个订阅检查缓存的结果。
特别是:
Mono<Token>
返回的getToken()
(这将触发令牌检索)。Mono<Token>
返回的getToken()
(将会触发令牌的重新检索。Mono<Token>
返回的getToken()
发生异常,则该异常将不会被缓存,因此将传播,并且下一个订阅将再次触发令牌检索所有这些都假定:
getToken()
在订户到达之前不做任何工作getToken()
检索每个订户的令牌还请注意,根据使用情况,您可能希望在令牌的到期日期之前将其过期,以解决时钟偏移问题。也就是说,要在新令牌实际到期之前抢先检索新令牌,以防止返回Token
,该令牌在下游有机会使用之前就已经到期。