You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring请求作用域下如何避免重复发起网络调用?

问题描述

我有一个Spring请求作用域(Request Scoped)的组件,用于发起网络调用获取数据:

@Component
@RequestScope
public class NetworkDataProvider {

    @Inject
    private ServiceClient serviceClient;    

    public Optional<List<String>> getSomeData() {
         return serviceClient.getSomeData(); // 发起网络请求获取数据
    }
}

我希望在多个其他组件中使用这些数据:

@Component
public class Component1 {
    
    @Inject
    private NetworkDataProvider networkDataProvider;

    public String getSomething() {
        Optional<List<String>> data = networkDataProvider.getSomeData();
        // 业务逻辑处理
    }
}
@Component
public class Component2 {
    
    @Inject
    private NetworkDataProvider networkDataProvider;

    public String getSomething() {
        Optional<List<String>> data = networkDataProvider.getSomeData();
        // 业务逻辑处理
    }
}

这些组件被用于控制器中:

@Controller
public class MyController {
    
    @Inject
    private Component1 component1;

    @Inject
    private Component2 component2;

    public ModelAndView mv() {
        String string1 = component1.getSomething();
        String string2 = component2.getSomething();
        // 组装视图
    }
}

目前由于ServiceClient会被两个不同的组件调用两次,因此会发起两次网络请求。请问在同一次请求中,避免多次发起网络调用并复用数据的最佳方式是什么?

最佳解决方案

方式一:在请求作用域组件内部缓存数据

既然NetworkDataProvider本身就是请求作用域的,直接在组件内部缓存获取到的数据,确保同一次请求内只调用一次网络接口:

@Component
@RequestScope
public class NetworkDataProvider {

    @Inject
    private ServiceClient serviceClient;    

    private Optional<List<String>> cachedData;

    public Optional<List<String>> getSomeData() {
         if (cachedData == null) {
             cachedData = serviceClient.getSomeData();
         }
         return cachedData;
    }
}

这种方式最简单直接,利用请求作用域组件的生命周期(同一次请求内实例唯一),第一次调用时发起网络请求并缓存结果,后续调用直接返回缓存值。

方式二:在控制器层提前获取数据并传递

如果不想修改NetworkDataProvider,可以在控制器中先获取数据,再传递给Component1和Component2:

@Controller
public class MyController {
    
    @Inject
    private Component1 component1;

    @Inject
    private Component2 component2;
    
    @Inject
    private NetworkDataProvider networkDataProvider;

    public ModelAndView mv() {
        Optional<List<String>> sharedData = networkDataProvider.getSomeData();
        String string1 = component1.getSomething(sharedData);
        String string2 = component2.getSomething(sharedData);
        // 组装视图
    }
}

同时修改Component1和Component2的方法,接收外部传入的数据:

@Component
public class Component1 {
    public String getSomething(Optional<List<String>> data) {
        // 业务逻辑处理
    }
}

这种方式适合需要明确控制数据流向的场景,避免组件之间隐式依赖请求作用域的缓存。

方式三:结合Spring缓存使用请求作用域缓存

如果项目中已经使用Spring Cache,可以配置一个请求作用域的缓存管理器,或者给getSomeData方法添加@Cacheable注解并指定缓存的作用域为请求级别:

@Component
@RequestScope
public class NetworkDataProvider {

    @Inject
    private ServiceClient serviceClient;    

    @Cacheable(cacheNames = "requestScopedCache", key = "#root.methodName")
    public Optional<List<String>> getSomeData() {
         return serviceClient.getSomeData();
    }
}

需要确保缓存配置是请求作用域的(比如使用SimpleCacheManager结合ConcurrentMapCache,并将缓存Bean设置为@RequestScope),这样同一次请求内的多次调用会复用缓存结果,请求结束后缓存自动失效。

总结

推荐优先使用方式一,因为它最贴合现有代码结构,改动最小,且利用了请求作用域组件的天然特性,无需额外配置或调整数据流向。

内容的提问来源于stack exchange,提问作者Chirag Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 09:25:11