Spring boot 动态设置缓存expireAfterWrite属性-咖啡因和Spring WebFlux
我正在使用咖啡因缓存存储使用webClient WebFlux获得的授权令牌。我已将expireAfterWrite设置为application.yml文件中的硬编码值,如下所示:Spring boot 动态设置缓存expireAfterWrite属性-咖啡因和Spring WebFlux,spring-boot,kotlin,spring-webflux,spring-cache,caffeine-cache,Spring Boot,Kotlin,Spring Webflux,Spring Cache,Caffeine Cache,我正在使用咖啡因缓存存储使用webClient WebFlux获得的授权令牌。我已将expireAfterWrite设置为application.yml文件中的硬编码值,如下所示: spring: cache: cache-names: accessTokens caffeine: spec: expireAfterWrite=100m 令牌是使用带有Spring WebFlux的WebClient获得的,如下代码所示: @Autowired var cac
spring:
cache:
cache-names: accessTokens
caffeine:
spec: expireAfterWrite=100m
令牌是使用带有Spring WebFlux的WebClient获得的,如下代码所示:
@Autowired
var cacheManager: CacheManager? = null
override fun getAuthToken(): Mono<AccessToken> {
val map = LinkedMultiValueMap<String, String>()
map.add("client_id", clientId)
map.add("client_secret", clientSecret)
map.add("grant_type", "client_credentials")
var cachedVersion = this.cacheManager?.getCache("accessTokens");
if (cachedVersion?.get("tokens") != null) {
val token = cachedVersion.get("tokens")
return Mono.just(token?.get() as AccessToken)
} else {
return webClient.post()
.uri("/client-credentials/token")
.body(BodyInserters.fromFormData(map))
.retrieve()
.onStatus(HttpStatus::is5xxServerError) {
ClientLogger.logClientErrorResponse(it, errorResponse)
}
.onStatus(HttpStatus::is4xxClientError) {
ClientLogger.logClientErrorResponse(it, errorResponse)
}
.bodyToMono(AccessToken::class.java)
.doOnNext { response ->
// Set here the expiration time of the cache based on
// response.expiresIn
this.cacheManager?.getCache("accessTokens")?.put("tokens", response) }
.log()
}
}
任何想法都将不胜感激。//根据创建条目的时间设置生存期的策略
var expiresAfterCreate=新到期日(){
public long expireAfterCreate(字符串凭据、AccessToken令牌、long currentTime){
Duration Duration=token.expiresIn();
return-token.toNanos();
}
public long expireAfterUpdate(字符串凭据、AccessToken令牌、,
长currentTime,长currentDuration){
返回持续时间;
}
public long expireAfterRead(字符串凭据、AccessToken令牌、,
长currentTime,长currentDuration){
返回持续时间;
}
});
//基于未来的完全缓存
AsyncLoadingCache cache=caffee.newBuilder()
.expireAfter(ExpireAfterCreate)
.buildAsync((凭据,执行者)->{
Mono令牌=检索(凭证);
返回token.toFuture();
});
//从缓存中获取,如果不存在则加载,并转换为Mono
Mono getAuthToken(){
var token=cache.get(凭证);
返回Mono.fromFuture(令牌);
}
//根据创建条目的时间设置生存期的策略
var expiresAfterCreate=新到期日(){
public long expireAfterCreate(字符串凭据、AccessToken令牌、long currentTime){
Duration Duration=token.expiresIn();
return-token.toNanos();
}
public long expireAfterUpdate(字符串凭据、AccessToken令牌、,
长currentTime,长currentDuration){
返回持续时间;
}
public long expireAfterRead(字符串凭据、AccessToken令牌、,
长currentTime,长currentDuration){
返回持续时间;
}
});
//基于未来的完全缓存
AsyncLoadingCache cache=caffee.newBuilder()
.expireAfter(ExpireAfterCreate)
.buildAsync((凭据,执行者)->{
Mono令牌=检索(凭证);
返回token.toFuture();
});
//从缓存中获取,如果不存在则加载,并转换为Mono
Mono getAuthToken(){
var token=cache.get(凭证);
返回Mono.fromFuture(令牌);
}
使用本机API,可以通过在Mono
和CompletableFuture
之间转换,使用AsyncCache
,并通过expireAfter(expire)
评估条目来实现。当未来成为现实时,它将计算该值的过期时间。SpringCache可能过于局限,因为它不适用于最简单的用例之外的任何东西。谢谢@BenManes。你能给我举一个例子吗?或者你知道一篇文章吗?我可以看看,找到一个类似于你建议的解决方案。谢谢。使用本机API,可以通过在Mono
和CompletableFuture
之间转换,使用AsyncCache
,并通过expireAfter(expire)
评估条目来实现。当未来成为现实时,它将计算该值的过期时间。SpringCache可能过于局限,因为它不适用于最简单的用例之外的任何东西。谢谢@BenManes。你能给我举一个例子吗?或者你知道一篇文章吗?我可以看看,找到一个类似于你建议的解决方案。Thank.Thank Ben,在getAuthToken()方法中,如果令牌不存在(缓存为空),我应该能够调用webClient来正确地检索令牌,但是在检索令牌后,如何将其放入缓存中呢。我正在做类似的事情,但从未填充:.doOnNext{response->cache?.put(“accessTokens”,Mono.just(response.toFuture())}@D.B在本例中,buildAsync
方法接受未命中时调用的加载函数。这反映了Map.ComputeFabSent,如果您愿意,可以在呼叫站点使用它。在这里,缓存填充了未命中的未来,并返回它,直到条目过期,下一个调用将未命中并重复。我不太清楚Reactor或Spring,但您的示例在响应具体化时填充缓存。在矿井中,飞行中的未来是缓存的,这避免了当多个线程执行并发调用、未命中和加载时的“缓存踩踏”。如果future失败或解析为null
,则回调会将其从缓存中删除。如果成功,那么回调将调用Expiry
来设置条目的持续时间。谢谢@ben。构建缓存时填充缓存的问题在于,对象缓存是完整的webClient调用,而不是webClient在实现后获得的响应,因此每次都从缓存中获取一个新令牌。没有使用springboot中的CacheManager服务从Caffee设置expireAfter属性的方法吗?@D.B在springboot中,您可以在code()中设置缓存生成器,这应该允许您设置expireAfter
。由于缓存需要在过期时间内检查某些内容,因此您需要将其包含在值(例如包装器)中,或者在其他地方查找它。否则,在cache.policy().expireVariably()
下有put(k,v,duration)
和putIfAbsent(k,v,duration)
可以进行更多的手动控制。感谢Ben,在getAuthToken()方法中,如果没有令牌(缓存为空),我应该能够调用webClient来检索令牌,但是,当它被检索时,我如何将其放入缓存中呢。我正在做类似的事情,但从未填充:.doOnNext{response->cache?.put(“accessTokens”,Mono.just(response.toFuture())}@D.B在本例中,buildAsync
方法接受调用的加载函数
.doOnNext { response ->
// Set here the expiration time of the cache based on
// response.expiresIn
this.cacheManager?.getCache("accessTokens")?.put("tokens", response)
}