使 Mono 的缓存值失效的最佳方法是什么?

问题描述 投票:0回答:1

我会尝试尽可能简单地解释我的用例。在我的应用程序中调用外部 Web 服务之前,我使用 Spring Webflux WebClient 从令牌提供者请求 oauth 访问令牌,并且我正在缓存该值,以便下次需要时重用它。每当请求失败并出现错误代码 401 时,我想使缓存无效并使用新令牌重试。

一切工作正常,接受我不确定 Mono 的缓存失效。

如果缓存需要失效,存储在布尔变量中是个好主意吗?订阅 auth Mono 时重试时,无效缓存谓词将为 true,这将使缓存无效并完成新请求。

还有其他想法吗?

示例代码:

@Component
public class AccessTokenService {

    private final WebClient accessTokenClient;
    private final Mono<Token> accessTokenMono;
    private final AtomicBoolean cacheInvalidated = new AtomicBoolean();

    public AccessTokenService() {
        accessTokenClient = WebClient.builder()
                .baseUrl("example-token-uri")
                .build();

        accessTokenMono = initAccessTokenMono();
    }

    private Mono<Token> initAccessTokenMono() {
        return accessTokenClient.post()
                .uri(uriBuilder -> uriBuilder
                        // Some credentials as parameters
                        .build())
                .retrieve()
                .bodyToMono(Token.class)
                // Always set cache invalidated to false when we get the response
                .doOnSuccess(token -> cacheInvalidated.set(false))
                .cacheInvalidateIf(accessToken -> cacheInvalidated.get());
    }

    public Mono<Token> getAccessTokenMono() {
        // Shared for all requests
        return accessTokenMono;
    }

// Called on 401
    public void setCacheInvalidated() {
        // Sets the predicate to true. For the next subscription the cache will be invalidated and a new request to the token provider will occur
        cacheInvalidated.set(true);
    }
}

spring spring-webflux netty reactor
1个回答
0
投票

与其尝试使脏标志的状态与

Mono
的有效性保持同步,为什么不在检测到 401 时简单地换入新的
Mono
呢?我还让它通过
cache()
定期刷新令牌,但这并不是您想要执行的操作的明确要求。

@Component
public class AccessTokenService {
    private static final Duration TOKEN_REFRESH_INTERVAL = Duration.ofHours(1);
    private final WebClient accessTokenClient;
    private final AtomicReference<Mono<Token>> accessTokenMono = new AtomicReference<>();

    public AccessTokenService() {
        accessTokenClient = WebClient.builder()
            .baseUrl("example-token-uri")
            .build();

        accessTokenMono.set(initAccessTokenMono());
    }

    private Mono<Token> initAccessTokenMono() {
        return accessTokenClient.post()
            .uri(uriBuilder -> uriBuilder
                // Some credentials as parameters
                .build())
            .retrieve()
            .bodyToMono(Token.class)
            .cache(token -> TOKEN_REFRESH_INTERVAL,         // refresh every interval
                exc -> Duration.ZERO, () -> Duration.ZERO); // don't cache exceptions or empties
    }

    public Mono<Token> getAccessTokenMono() {
        // Shared for all requests
        return accessTokenMono.get();
    }

    // Called on 401
    public void setCacheInvalidated() {
        // Plug in a new Mono so subsequent requests get a new token
        accessTokenMono.set(initAccessTokenMono());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.