如何非阻塞将带Map属性的Mono<User>转换为Mono<VehiclesInfo>
问题场景
开发中定义如下DTO类:
public class User { int id; Map<String, Car> carsMap; public Map<String, Car> getCarsMap() { return carsMap; } } public class Car { String carName; public String getCarName() { return carName; } } // 接口返回对象 public class VehiclesInfo { List<String> vehicleName; public void setVehicleName(List<String> vehicleName) { this.vehicleName = vehicleName; } }
通过userId查询数据库的返回值为Mono<User>类型,接口要求返回Mono<VehiclesInfo>类型,转换规则为:提取Mono<User>中carsMap存储的所有carName,组装为List赋值给VehiclesInfo的vehicleName属性,最终包装为Mono<VehiclesInfo>返回。
当前实现调用了blockOptional()触发阻塞操作,不符合响应式非阻塞要求,原有实现代码如下:
// userMono为数据库查询返回结果 Mono<User> userMono = getUserInfoById(userId); Optional<User> userOptional = userMono.blockOptional(); if (userOptional.isPresent()) { User user1 = userOptional.get(); Flux<Car> carFlux = Flux.fromIterable(user1.getCarsMap().keySet()) .flatMap(i -> { Car c = new Car(); c.setCarName(i); return Mono.just(c); }); carFlux.subscribe(c -> System.out.println(c.getCarName())); }
非阻塞实现方案
响应式编程规范中禁止在流处理链路中主动调用block()、blockOptional()这类阻塞方法,所有数据转换逻辑需要通过响应式操作符在流内部完成,最终由框架触发订阅,业务代码不需要手动调用subscribe()。
基础实现
import java.util.stream.Collectors; Mono<User> userMono = getUserInfoById(userId); Mono<VehiclesInfo> vehiclesInfoMono = userMono.map(user -> { VehiclesInfo vehiclesInfo = new VehiclesInfo(); // 遍历carsMap的value,提取所有carName收集为List List<String> carNameList = user.getCarsMap() .values() .stream() .map(Car::getCarName) .collect(Collectors.toList()); vehiclesInfo.setVehicleName(carNameList); return vehiclesInfo; });
空安全兼容版本
如果需要兼容carsMap为null的场景,增加空判断避免空指针:
import java.util.Collections; import java.util.Optional; import java.util.stream.Collectors; Mono<VehiclesInfo> safeVehiclesInfoMono = userMono.map(user -> { VehiclesInfo vehiclesInfo = new VehiclesInfo(); List<String> carNameList = Optional.ofNullable(user.getCarsMap()) .map(carMap -> carMap.values() .stream() .map(Car::getCarName) .collect(Collectors.toList())) .orElse(Collections.emptyList()); vehiclesInfo.setVehicleName(carNameList); return vehiclesInfo; });
原有实现问题说明
- 遍历
carsMap.keySet()的逻辑错误:Map的key是String类型的索引键,carName实际存储在value位的Car对象属性中,直接遍历values()取值即可 - 纯内存的集合转换不需要额外创建Flux处理,直接用JDK Stream完成转换性能更高,代码更简洁
- 业务代码中不要手动订阅响应式流,WebFlux等响应式框架会在响应返回时自动触发订阅,手动提前订阅会导致流执行时机不可控,甚至出现请求上下文丢失的问题
内容的提问来源于stack exchange,提问作者AlwaysLearning
相关产品推荐
相关产品推荐

