遍历Mono<Map<String,String>>获取目标对象 解决subscribe结果不一致问题
问题根因
偶发赋值失败是subscribe()的异步非阻塞特性导致的:调用subscribe()后不会等待流内的赋值逻辑执行完成,会直接向下执行。如果后续代码提前读取了complianceResponse的country字段,就会出现还未赋值的情况,只有流逻辑恰好先于字段读取完成时才能拿到正确结果,最终表现为时好时坏。
解决方案
分两种使用场景选择适配方案:
场景1:方法必须保持void返回值(调用方不在反应式上下文)
将末尾的subscribe()替换为block(),强制等待流内所有逻辑执行完成后再返回,保证赋值操作一定在方法返回前执行完成:
private void generateComplianceResponse(BOLCompliance complianceResponse) { locationsMap().flatMap(entry -> { Set<Map.Entry<String, String>> set = entry.entrySet(); set.forEach(e -> { if (complianceResponse.getCompliancePort().substring(0, 2).equalsIgnoreCase(e.getKey())) { complianceResponse.setCountry(e.getValue()); } }); return Mono.just(complianceResponse); }).doOnNext(System.out::println) // 替换subscribe为block,阻塞等待执行完成 .block(); }
场景2:方法在反应式上下文调用(比如WebFlux接口/反应式业务流内)
不要在方法内部订阅,修改方法返回值为Mono<BOLCompliance>,把流交给上层订阅处理,避免反应式上下文内不必要的阻塞:
private Mono<BOLCompliance> generateComplianceResponse(BOLCompliance complianceResponse) { return locationsMap().map(entry -> { // 这里没有嵌套Mono,用map即可,无需flatMap Set<Map.Entry<String, String>> set = entry.entrySet(); set.forEach(e -> { if (complianceResponse.getCompliancePort().substring(0, 2).equalsIgnoreCase(e.getKey())) { complianceResponse.setCountry(e.getValue()); } }); return complianceResponse; }).doOnNext(System.out::println); }
可选优化建议
你当前的locationsMap()返回的是固定内容的Map,可以提前初始化静态常量,避免每次调用重复创建对象:
private static final Map<String, String> LOCATION_MAP = Map.of( "DK", "Denmark", "UK", "United Kingdom" ); private Mono<Map<String,String>> locationsMap(){ return Mono.just(LOCATION_MAP); }
内容的提问来源于stack exchange,提问作者Mira Devi
相关产品推荐
相关产品推荐

