在Quarkus中结合Mutiny异步使用RestClient并组合多请求结果构建自定义响应
在Quarkus中结合Mutiny异步使用RestClient并组合多请求结果构建自定义响应
嘿,刚接触响应式编程+Quarkus的话,确实需要花点时间摸透Mutiny的Uni怎么玩——我当初刚上手的时候也纠结过怎么把多个RestClient的异步请求结果拼起来,给你分享几种实用的做法,刚好匹配你的场景:
首先,先确认你已经正确注入了RestClient(Quarkus会自动处理代理,只要你加了@RestClient注解就行):
@Inject @RestClient MyRestClient myRestClient;
场景1:三个请求无依赖,并行执行后组合结果
这种情况是最常见的,三个接口调用互相不依赖,我们可以让它们同时跑,等所有结果都回来再组装自定义响应,效率最高:
public Uni<MyResponseType> buildCustomResponse() { // 先定义三个异步请求(此时还没执行,Uni是懒加载的) Uni<String> stringDataUni = myRestClient.getStringData(); Uni<CustomResponseType> customDataUni = myRestClient.getCustomData(); Uni<AnotherResponseType> anotherDataUni = myRestClient.getAnotherData(); // 用Uni.combine把三个请求的结果组合起来 return Uni.combine().all().unis(stringDataUni, customDataUni, anotherDataUni) .asTuple() // 把结果打包成Tuple,方便按顺序取 .map(tuple -> { MyResponseType finalResponse = new MyResponseType(); // 从第一个请求结果取字符串 finalResponse.setSomeString(tuple.getItem1()); // 从第二个请求结果里提取你需要的Integer字段 finalResponse.setSomeInteger(tuple.getItem2().getTargetIntegerField()); // 从第三个请求结果提取另一个Integer字段 finalResponse.setSomeOtherInteger(tuple.getItem3().getAnotherTargetIntegerField()); return finalResponse; }); }
这里的核心是Uni.combine().all().unis(),它会并行触发所有请求,只有当三个请求都成功完成后才会进入map阶段组装结果,不会有任何请求等待另一个的情况,性能拉满。
场景2:请求之间有依赖关系
如果某个请求的参数需要依赖前一个请求的结果,那我们可以用flatMap来链式处理,比如假设getCustomData()需要用到getStringData()返回的字符串当参数:
public Uni<MyResponseType> buildCustomResponseWithDependency() { // 先执行第一个请求,拿到结果后再触发后续请求 return myRestClient.getStringData() .flatMap(stringResult -> { // 用第一个请求的结果作为参数发起第二个请求(这里假设接口支持传参) Uni<CustomResponseType> customDataUni = myRestClient.getCustomData(stringResult); // 第三个请求还是独立的,并行执行 Uni<AnotherResponseType> anotherDataUni = myRestClient.getAnotherData(); // 组合后面两个请求的结果,同时带上第一个请求的字符串 return Uni.combine().all().unis(customDataUni, anotherDataUni) .asTuple() .map(tuple -> { MyResponseType finalResponse = new MyResponseType(); finalResponse.setSomeString(stringResult); finalResponse.setSomeInteger(tuple.getItem1().getTargetIntegerField()); finalResponse.setSomeOtherInteger(tuple.getItem2().getAnotherTargetIntegerField()); return finalResponse; }); }); }
flatMap的作用是把前一个Uni的结果转换成新的Uni,这样就能实现“先做A,再用A的结果做B和C”的逻辑。
额外补充:异常处理
实际开发中肯定要考虑请求失败的情况,你可以给每个Uni单独加异常处理,也可以在组合后的Uni上统一处理:
// 给单个请求加异常 fallback Uni<String> stringDataUni = myRestClient.getStringData() .onFailure().recoverWithItem("默认字符串"); // 或者在组合后的结果统一处理 return Uni.combine().all().unis(stringDataUni, customDataUni, anotherDataUni) .asTuple() .map(...) .onFailure().recoverWithItem(failure -> { // 这里可以返回兜底的响应,或者抛出自定义异常 MyResponseType fallbackResponse = new MyResponseType(); fallbackResponse.setSomeString("兜底字符串"); fallbackResponse.setSomeInteger(0); fallbackResponse.setSomeOtherInteger(0); return fallbackResponse; });
最后提个小细节:Mutiny的Uni是懒加载的,也就是说,只有当这个Uni被订阅的时候(比如你在REST接口里直接返回这个Uni,Quarkus会自动帮你订阅),所有的请求才会真正发起,不用手动触发~
备注:内容来源于stack exchange,提问作者Israel77
相关产品推荐
相关产品推荐

