Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring boot 动态设置缓存expireAfterWrite属性-咖啡因和Spring WebFlux_Spring Boot_Kotlin_Spring Webflux_Spring Cache_Caffeine Cache - Fatal编程技术网

Spring boot 动态设置缓存expireAfterWrite属性-咖啡因和Spring WebFlux

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

我正在使用咖啡因缓存存储使用webClient WebFlux获得的授权令牌。我已将expireAfterWrite设置为application.yml文件中的硬编码值,如下所示:

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) 
                 }