13.1.2 定义响应式 Repository
在第 3 章和第 4 章中,我们将 Repository 定义为扩展 Spring Data 的 CrudRepository 接口。但那个基本 Repository 接口处理的是单个对象和可遍历集合。相反,我们希望响应式 Repository 能够处理 Mono 和 Flux 对象。
这就是为什么 Spring 提供了 ReactiveCrudepository 来定义响应式 Repository。ReactiveCrudepository 的操作与 CrudRepository 非常相似。要创建响应式 Repository,需扩展 ReactiveCrudepository 接口,例如:
package tacos.data;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import tacos.TacoOrder;
public interface OrderRepository
extends ReactiveCrudRepository<TacoOrder, Long> {
}
从表面上看,这个 OrderRepository 与我们在第 3 章和第 4 章中定义的 OrderRepository 之间的唯一区别是,它扩展了 ReactiveCrudRepository,而不是 CrudRepository。但是最显著不同其实是,这个方法返回 Mono 和 Flux 类型,而不是单个 TacoOrder 或 Iterable<TacoOrder>
。举两个例子:findById()
方法返回 Mono<TacoOrder>
,findAll()
返回 Flux<TacoOrder>
。
要了解此响应式 Repository 在实际如何工作,假设您希望获取所有 TacoOrder 对象,并将其名称打印到标准输出。这种情况下,您可以 编写一些代码,如清单 13.4 所示。
清单 13.4 调用响应式 Repository 方法。
@Autowired
OrderRepository orderRepo;
...
orderRepository.findAll()
.doOnNext(order -> {
System.out.println(
"Deliver to: " + order.getDeliveryName());
})
.subscribe();
在这里,对 findAll()
的调用返回一个 Flux<TacoOrder>
。我们在其上添加了一个 doOnNext()
方法以打印收货人名称。最后,调用 subscribe()
启动了数据传输。
在第 3 章的 Spring Data JDBC 示例中,TacoOrder 是 Taco 的聚合根。因此,Taco 对象作为 TacoOrder 的一部分被持久化了,而没有必要定义一个专门用于 Taco 持久性的 Repository。但是 Spring Data R2DBC 不能以这种方式支持聚合,因此我们需要一个 TacoRepository,通过它持久化 Taco 对象。这个 Repository 请参见清单 13.5。
清单 13.5 使用响应式 Repository 持久化 Taco 对象。
package tacos.data;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import tacos.Taco;
public interface TacoRepository
extends ReactiveCrudRepository<Taco, Long> {
}
如您所见,TacoRepository 与 OrderRepository 没有太大区别。它扩展 ReactiveCrudepository,在使用 Taco 持久化时为我们提供响应式类型。这里没有太多可说的。
另一方面,IngredientRepository 稍微有趣一些,如清单 13.6 所示。
清单 13.6 使用响应式 Repository 持久化 Ingredient 对象。
package tacos.data;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Mono;
import tacos.Ingredient;
public interface IngredientRepository
extends ReactiveCrudRepository<Ingredient, Long> {
Mono<Ingredient> findBySlug(String slug);
}
与我们的其他两个响应式 Repository 一样,IngredientRepository 扩展了 ReactiveCrudRepository。但是因为我们可能需要一种基于 slug 值来查找 Ingredient 对象的方法,IngredientRepository 包含一个 findBySlug()
方法,该方法返回一个 Mono<Ingredient>
。
现在让我们看看如何编写测试类,来验证我们的 Repository 是否工作。