Spring开发中按URL缓存创建好的WebClient实例是否是合理方案?
WebClient实例缓存合理性说明
核心结论
针对特定配置的WebClient实例做缓存是完全合理的做法:
- WebClient是官方设计的不可变、线程安全类,实例一旦创建完成就可以在多线程环境下安全复用,不存在并发问题
- 反复创建WebClient实例会带来不必要的初始化开销,在你需要调用大量不同外部接口的场景下,缓存复用能有效降低资源消耗,提升接口调用性能
你当前代码存在的问题
你现有的@Cacheable配置存在逻辑缺陷:
@Cacheable(value = "somevalue", cacheManager = "cachemnager", key = "#url") public WebClient getWebClient(String url, Map<String, String> headers,List<ExchangeFilterFunction> filterFunctions) { return WebClient.builder() .baseUrl(url) .defaultHeaders(addsome headers) .filters(list -> list.addAll(filterFunctions)) .build(); }
问题点:缓存key仅用了
url参数,但是headers、filterFunctions两个参数也会影响生成的WebClient配置,如果同一个url传入不同的header或过滤器,会拿到不符合当前配置要求的缓存实例,导致业务错误。
优化建议
- 调整缓存key规则
如果你的headers、filterFunctions是和url绑定的固定配置,需要将两个参数也纳入缓存key的计算:// 注意:该写法要求传入的headers、ExchangeFilterFunction实现类都正确重写了equals和hashCode方法 @Cacheable(value = "somevalue", cacheManager = "cachemnager", key = "#url + '_' + #headers.hashCode() + '_' + #filterFunctions.hashCode()") - 分离静态配置和动态参数
如果headers、filterFunctions是每次请求都会变化的动态内容,不要将其设置为WebClient的全局默认配置,改为在单次请求调用时传入即可:// 缓存方法仅保留固定的url配置 @Cacheable(value = "webClientCache", key = "#url") public WebClient getWebClient(String url) { return WebClient.builder().baseUrl(url).build(); } // 调用时动态设置header、过滤器 webClient.get() .uri("/xxx") .headers(h -> h.setAll(dynamicHeaders)) .retrieve() - 补充说明
Spring自动注入的WebClient.Builder默认会复用底层的HttpClient连接池、事件循环组等核心资源,就算你创建多个WebClient实例,也不会重复初始化底层IO资源,缓存的收益主要是减少Builder重复配置、WebClient上下文初始化的开销,无需担心多实例带来的资源浪费问题。
内容的提问来源于stack exchange,提问作者Piyush Singh
相关产品推荐
相关产品推荐

