提问者:小点点

确保在应用程序启动之前加载数据|Spring webflux


我有一个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?


共1个答案

匿名用户

当前呈现的应用程序架构解决方案是固有阻塞设计的典型示例。

如果向api发出的第一个请求需要这些项目就位,那么我们必须确保它们已经就位,然后才能接受请求。确保这一点的唯一方法是< code >阻塞,直到实际上已经获取并存储了项目。

由于设计本身就是模块化的,我们需要重新思考我们的方法。

我们想要的是尽快使服务可用于请求。我们可以通过使用缓存来解决这个问题,缓存将在发出第一个请求时被填充。

这意味着应用程序启动时有一个空的缓存。例如,这个缓存可以是@Component,因为springbean默认情况下是singleton。

这些步骤将是:

  • 服务启动,缓存为空
  • 服务接收其第一个请求
  • 检查缓存中是否有数据
  • 如果数据过时,请逐出缓存
  • 如果缓存为空,则从我们的源获取数据
  • 用我们获取的数据填充缓存
  • 对放置在缓存中的数据设置 TTL(生存时间)
  • 将数据返回到调用客户端

第二个要求:

  • 请求进入服务
  • 检查缓存中是否有数据
  • 检查数据是否陈旧
  • 如果没有,则获取数据并将其返回给主叫用户

有几种缓存解决方案,spring有其@Cachable注释,默认情况下只是一个键值存储,但可以与redis等外部解决方案配对。

其他解决方案可以是谷歌番石榴,这在他们的github上有很好的阅读效果。

这种类型的解决方案被称为用内存换cpu。我们获得了启动时间和快速请求(cpu),但代价是我们将花费更多的内存来将数据保存在缓存中。