我正在学习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序列化器。
答案 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 3有addition,可以与caffeine,jcache等现代内存缓存进行流畅集成。使用该技术,您将能够缓存数据容易:
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();
}