如何在 spring WebFlux 中合并 Mono Objects 的结果?
How to consolidate the results of Mono Objects in spring WebFlux?
请查看以下来自使用 RestTemplate 的控制器(已添加注释)的代码:
@GetMapping("/{courseid}")
public Course getCourseDetails(@PathVariable Long courseid) {
// Get Course info (ID, Name, Description) from pre-populated Array List
CourseInfo courseInfo = getCourseInfo(courseid);
// Get Price info of a course from another microservice using RESTTemplate
Price price = restTemplate.getForObject("http://localhost:8002/price/"+courseid, Price.class);
// Get enrollment info of a course from another microservice using RESTTemplate
Enrollment enrollment = restTemplate.getForObject("http://localhost:8003/enrollment/"+courseid, Enrollment.class);
//Consolidate everything in to Course object and send it as response
return new Course(courseInfo.getCourseID(), courseInfo.getCourseName(), courseInfo.getCourseDesc(), price.getDiscountedPrice(),
enrollment.getEnrollmentOpen());
}
现在我正尝试使用反应式编程来实现同样的目标。我现在使用 Web-Flux 的 WebClient 和 Mono。但是,我对如何组合结果感到困惑?看看下面的代码(只是到处使用 Mono。其余代码保持不变)
@GetMapping("/{courseid}")
public Mono<Course> getCourseDetails(@PathVariable Long courseid) {
// Get Course info (ID, Name, Description) from pre-populated Array List
CourseInfo courseInfo = getCourseInfo(courseid);
// Get Price info of a course from another microservice using RESTTemplate
Mono<Price> price = webClient.get().uri("http://localhost:8002/price/{courseid}/",courseid).retrieve().bodyToMono(Price.class);
// Get enrollment info of a course from another microservice using RESTTemplate
Mono<Enrollment> inventory = webClient.get().uri("http://localhost:8003/enrollment/{courseid}/",courseid).retrieve().bodyToMono(Enrollment.class);
//Question : How do we Consolidate everything and form a Mono<Course> object and send it as response?
}
问题 1:我们如何合并所有内容并形成一个 Mono 对象并将其作为响应发送?
问题2:语句“CourseInfo courseInfo = getCourseInfo(courseid);”是否正确?导致阻塞操作?
谢谢!
restTemplate.getForObject
returns 简单对象 - 在您的情况下 Price
或 Enrollment
。要将它们转换为 Mono,您可以简单地 Mono.just(object)
,但是更好的解决方案是切换到 Webclient,这是 Spring Reactive
的默认 HTTP 客户端
getCourseInfo
这取决于这个方法背后的逻辑是什么。确定该方法后面是否存在 JDBC 连接,它正在阻塞。
要对 Mono<Course>
做出最终回应,您应该考虑 zip operator 这将对您有所帮助。
例如:
Mono<Course> courseMono = Mono.zip(price, enrollment)
.map(tuple -> new Course(courseInfo, tuple.getT1(), tuple.getT2()));
回答:
Question 1 : How do we Consolidate everything and form a Mono object and send it as response?
Mono.zip(..) 是您需要合并两个结果的内容。此图来自doc :
请注意,如果 A 或 1 之一为空,zip
将导致 空 Mono!使用 switchIfEmpty
/defaultIfEmpty
来防止这种情况。
因此代码如下所示:
@GetMapping("/{courseid}")
public Mono<Course> getCourseDetails(@PathVariable Long courseid) {
CourseInfo courseInfo = getCourseInfo(courseid);
Mono<Price> priceMono = webClient.get().uri("http://localhost:8002/price/{courseid}/",courseid).retrieve().bodyToMono(Price.class);
Mono<Enrollment> enrollmentMono = webClient.get().uri("http://localhost:8003/enrollment/{courseid}/",courseid).retrieve().bodyToMono(Enrollment.class);
return Mono.zip(priceMono, enrollmentMono).map(t -> new Course(courseInfo.getCourseID(), courseInfo.getCourseName(), courseInfo.getCourseDesc(), t.getT1().getDiscountedPrice(),
t.getT2().getEnrollmentOpen()));
}
现在回答:
Question 2 : Does the statement "CourseInfo courseInfo = getCourseInfo(courseid);" cause blocking operation?
既然你提到了Get Course info (ID, Name, Description) from pre-populated Array List
,如果它只是一个包含课程信息的内存数组,那么它就不会阻塞。
但是(正如@mslowiak 也提到的),如果getCourseInfo
包含涉及查询数据库的逻辑,请确保您没有使用阻塞JDBC 驱动程序。如果是这样,那么使用 Webflux 和 Reactor 就没有意义了。 如果是这样,请使用 Spring R2DBC。
请查看以下来自使用 RestTemplate 的控制器(已添加注释)的代码:
@GetMapping("/{courseid}")
public Course getCourseDetails(@PathVariable Long courseid) {
// Get Course info (ID, Name, Description) from pre-populated Array List
CourseInfo courseInfo = getCourseInfo(courseid);
// Get Price info of a course from another microservice using RESTTemplate
Price price = restTemplate.getForObject("http://localhost:8002/price/"+courseid, Price.class);
// Get enrollment info of a course from another microservice using RESTTemplate
Enrollment enrollment = restTemplate.getForObject("http://localhost:8003/enrollment/"+courseid, Enrollment.class);
//Consolidate everything in to Course object and send it as response
return new Course(courseInfo.getCourseID(), courseInfo.getCourseName(), courseInfo.getCourseDesc(), price.getDiscountedPrice(),
enrollment.getEnrollmentOpen());
}
现在我正尝试使用反应式编程来实现同样的目标。我现在使用 Web-Flux 的 WebClient 和 Mono。但是,我对如何组合结果感到困惑?看看下面的代码(只是到处使用 Mono。其余代码保持不变)
@GetMapping("/{courseid}")
public Mono<Course> getCourseDetails(@PathVariable Long courseid) {
// Get Course info (ID, Name, Description) from pre-populated Array List
CourseInfo courseInfo = getCourseInfo(courseid);
// Get Price info of a course from another microservice using RESTTemplate
Mono<Price> price = webClient.get().uri("http://localhost:8002/price/{courseid}/",courseid).retrieve().bodyToMono(Price.class);
// Get enrollment info of a course from another microservice using RESTTemplate
Mono<Enrollment> inventory = webClient.get().uri("http://localhost:8003/enrollment/{courseid}/",courseid).retrieve().bodyToMono(Enrollment.class);
//Question : How do we Consolidate everything and form a Mono<Course> object and send it as response?
}
问题 1:我们如何合并所有内容并形成一个 Mono 对象并将其作为响应发送?
问题2:语句“CourseInfo courseInfo = getCourseInfo(courseid);”是否正确?导致阻塞操作?
谢谢!
的默认 HTTP 客户端restTemplate.getForObject
returns 简单对象 - 在您的情况下Price
或Enrollment
。要将它们转换为 Mono,您可以简单地Mono.just(object)
,但是更好的解决方案是切换到 Webclient,这是 Spring ReactivegetCourseInfo
这取决于这个方法背后的逻辑是什么。确定该方法后面是否存在 JDBC 连接,它正在阻塞。要对
Mono<Course>
做出最终回应,您应该考虑 zip operator 这将对您有所帮助。
例如:
Mono<Course> courseMono = Mono.zip(price, enrollment)
.map(tuple -> new Course(courseInfo, tuple.getT1(), tuple.getT2()));
回答:
Question 1 : How do we Consolidate everything and form a Mono object and send it as response?
Mono.zip(..) 是您需要合并两个结果的内容。此图来自doc :
请注意,如果 A 或 1 之一为空,zip
将导致 空 Mono!使用 switchIfEmpty
/defaultIfEmpty
来防止这种情况。
因此代码如下所示:
@GetMapping("/{courseid}")
public Mono<Course> getCourseDetails(@PathVariable Long courseid) {
CourseInfo courseInfo = getCourseInfo(courseid);
Mono<Price> priceMono = webClient.get().uri("http://localhost:8002/price/{courseid}/",courseid).retrieve().bodyToMono(Price.class);
Mono<Enrollment> enrollmentMono = webClient.get().uri("http://localhost:8003/enrollment/{courseid}/",courseid).retrieve().bodyToMono(Enrollment.class);
return Mono.zip(priceMono, enrollmentMono).map(t -> new Course(courseInfo.getCourseID(), courseInfo.getCourseName(), courseInfo.getCourseDesc(), t.getT1().getDiscountedPrice(),
t.getT2().getEnrollmentOpen()));
}
现在回答:
Question 2 : Does the statement "CourseInfo courseInfo = getCourseInfo(courseid);" cause blocking operation?
既然你提到了Get Course info (ID, Name, Description) from pre-populated Array List
,如果它只是一个包含课程信息的内存数组,那么它就不会阻塞。
但是(正如@mslowiak 也提到的),如果getCourseInfo
包含涉及查询数据库的逻辑,请确保您没有使用阻塞JDBC 驱动程序。如果是这样,那么使用 Webflux 和 Reactor 就没有意义了。 如果是这样,请使用 Spring R2DBC。