我有一个spring webflux应用程序。
我正在将一些列表从数据库加载到 bean 中。我有两种方法可以实现此 bean 的加载。
方法1:反应方式
@Bean
public List<Item> getItemList() throws IOException {
List<Item> itemList = new ArrayList<>();
itemRespository.findAll().collectList().subscribe(itemList::addAll);
return itemList;
}
方法二:阻塞方式
@Bean
public List<Item> getItemList() throws IOException {
List<Item> itemList = itemRespository.findAll().collectList().block();
return itemList;
}
现在,由于我希望我的应用程序是被动的,所以我不想使用阻塞方式。但是我通过控制器公开的endpoint依赖于这个bean的数据。
@RestController
public class SomeController{
@Autowired
private List<items> getItemList;
@GetMapping('/endpoint')
public void process(){
List list = getItemList; //this may not get initialzed as the bean loading is reactive
//some more code
}
}
因此,在反应式方法的情况下,可能会发生有人可能会调用我的endpoint(因为应用程序已经启动并准备好服务请求),而由于某种原因,可能会发生我的列表尚未从数据库中检索(可能是任何原因,例如:数据库服务器慢等)。),为调用我的endpoint的用户产生不一致的结果(endpoint又依赖于这个bean)。
我正在寻找这种情况的解决方案。
编辑:更精确的问题是,我应该在我的应用程序中反应性地加载这些 bean,而我公开的endpoint依赖于这些 bean?
当前呈现的应用程序架构解决方案是固有阻塞设计的典型示例。
如果向api发出的第一个请求需要这些项目就位,那么我们必须确保它们已经就位,然后才能接受请求。确保这一点的唯一方法是< code >阻塞,直到实际上已经获取并存储了项目。
由于设计本身就是模块化的,我们需要重新思考我们的方法。
我们想要的是尽快使服务可用于请求。我们可以通过使用缓存来解决这个问题,缓存将在发出第一个请求时被填充。
这意味着应用程序启动时有一个空的缓存。例如,这个缓存可以是@Component
,因为springbean默认情况下是singleton。
这些步骤将是:
第二个要求:
有几种缓存解决方案,spring有其@Cachable
注释,默认情况下只是一个键值存储,但可以与redis等外部解决方案配对。
其他解决方案可以是谷歌番石榴
,这在他们的github上有很好的阅读效果。
这种类型的解决方案被称为用内存换cpu。我们获得了启动时间和快速请求(cpu),但代价是我们将花费更多的内存来将数据保存在缓存中。