如何将SpringBoot REST端点转换为Spring WebFlux响应式端点
Spring Boot MVC接口转WebFlux正确实现
原有代码问题说明
你当前改写的代码存在三个核心问题:
- 响应式流是惰性执行的,你创建的
defaultMono没有组装到最终返回的链路中,不会被框架订阅触发执行 - 没有将响应内容包装为
Mono<ResponseEntity>类型返回,同步返回ResponseEntity对象不符合WebFlux接口的响应式返回要求 - 单独调用
defaultMono.log()不会生效,操作符需要绑定到最终返回的流链路上才会执行
正确实现代码
写法1:和MVC逻辑一致的最简实现
如果只是打印接口入口日志,不需要感知响应式流的执行生命周期,直接和MVC写法一致打日志即可,代码如下:
import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @Slf4j @RestController public class HelloController { @GetMapping("/helloWorld") public Mono<ResponseEntity<String>> helloWorld() { // 进入Controller方法时直接打印入口日志,行为和Spring MVC完全一致 log.info("Entered hello world"); // 将响应实体包装到Mono中返回即可 return Mono.just(ResponseEntity.ok("Hello World")); } }
写法2:响应式链路内打日志
如果需要在流执行过程中打日志、或者后续链路有异步线程切换、需要绑定流生命周期打日志,使用Reactor提供的副作用操作符实现:
import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @Slf4j @RestController public class HelloController { @GetMapping("/helloWorld") public Mono<ResponseEntity<String>> helloWorld() { return Mono.just("Hello World") // doOnNext是专门用于打日志、埋点等不修改流数据的副作用操作符,流执行到该步骤时会触发 .doOnNext(content -> log.info("Entered hello world in controller")) // 将返回的字符串内容包装为ResponseEntity .map(ResponseEntity::ok) // 调试场景可加内置log()操作符,会自动打印流订阅、请求、数据发送、完成、异常等全生命周期日志 // .log() ; } }
关键注意点
- 所有操作符必须组装到最终返回的流链路上:单独创建Mono、单独调用操作符但不接入返回链路,不会有任何执行效果
- 日志打印优先使用
doOnNext/doOnSubscribe/doOnError这类副作用操作符,不要在map/flatMap这类数据转换操作符中写日志逻辑,语义不匹配 - 返回值泛型不要用原生
Mono<ResponseEntity>,明确指定响应体的泛型类型(比如示例中的String),避免Spring序列化时出现类型推断错误 - 内置
.log()操作符会打印大量流生命周期日志,仅适合调试使用,生产环境非必要不要开启,避免产生冗余日志
内容的提问来源于stack exchange,提问作者Hermes Chavez
相关产品推荐
相关产品推荐

