Spring Webflux和@Cacheable - Mono / Flux类型的缓存结果的正确方法

时间:2018-01-08 18:53:50

标签: spring-boot spring-cache spring-webflux

我正在学习Spring WebFlux,在编写示例应用程序时,我发现了与Reactive类型(Mono / Flux)结合Spring Cache的问题。

考虑以下代码片段(在Kotlin中):

@Repository
interface TaskRepository : ReactiveMongoRepository<Task, String>

@Service
class TaskService(val taskRepository: TaskRepository) {

    @Cacheable("tasks")
    fun get(id: String): Mono<Task> = taskRepository.findById(id)
}

这种有效且安全的缓存方法调用方式是返回Mono还是Flux?也许还有其他原则可以做到这一点?

以下代码正在使用SimpleCacheResolver,但默认情况下使用Redis失败,因为Mono不是Serializable。为了使它们工作,例如需要使用Kryo序列化器。

3 个答案:

答案 0 :(得分:16)

哈克方式

目前,@Cacheable与Reactor 3没有流畅的整合。 但是,您可以通过向返回的.cache()

添加Mono运算符来绕过该问题
@Repository
interface TaskRepository : ReactiveMongoRepository<Task, String>

@Service
class TaskService(val taskRepository: TaskRepository) {

    @Cacheable("tasks")
    fun get(id: String): Mono<Task> = taskRepository.findById(id).cache()
}

从<{1}}数据返回的 hack 缓存和共享。反过来,spring cacheable将缓存返回的taskRepository的引用,然后返回该引用。换句话说,它是一个保存缓存的单声道缓存:)。

Reactor Addons Way

Reactor 3有addition,可以与caffeinejcache等现代内存缓存进行流畅集成。使用该技术,您将能够缓存数据容易:

Mono
  

注意:Reactor插件缓存自己的抽象,@Repository interface TaskRepository : ReactiveMongoRepository<Task, String> @Service class TaskService(val taskRepository: TaskRepository) { @Autowire CacheManager manager; fun get(id: String): Mono<Task> = CacheMono.lookup(reader(), id) .onCacheMissResume(() -> taskRepository.findById(id)) .andWriteWith(writer()); fun reader(): CacheMono.MonoCacheReader<String, Task> = key -> Mono.<Signal<Task>>justOrEmpty((Signal) manager.getCache("tasks").get(key).get()) fun writer(): CacheMono.MonoCacheWriter<String, Task> = (key, value) -> Mono.fromRunnable(() -> manager.getCache("tasks").put(key, value)); } ,因此,不要担心并遵循该约定

答案 1 :(得分:0)

我曾经使用过Oleh Dokuka的hacky解决方案效果很好,但有一个问题。您在Flux缓存中使用的Duration必须大于在“可缓存”缓存中的timetolive值。如果您不对Flux缓存使用持续时间,则它不会使它无效(Flux文档说“将这个Flux变成一个热信号源,并缓存最后发出的信号以供其他订户使用。”)。 因此,使Flux缓存2分钟和生存时间30秒可以是有效的配置。如果首先发生ehcahce超时,则会生成一个新的Flux缓存引用并将其使用。

答案 2 :(得分:0)

//在外观中:

targetAuditMode

//在服务层中:

public Mono<HybrisResponse> getProducts(HybrisRequest request) {
    return Mono.just(HybrisResponse.builder().build());
}

//在控制器中:

@Cacheable(cacheNames = "embarkations")
public HybrisResponse cacheable(HybrisRequest request) {
    LOGGER.info("executing cacheable");
    return null;
}

@CachePut(cacheNames = "embarkations")
public HybrisResponse cachePut(HybrisRequest request) {
    LOGGER.info("executing cachePut");
    return hybrisFacade.getProducts(request).block();
}