Spring WebFlux中@AfterReturning切面未正确触发问题求助
问题原因
Spring WebFlux 基于反应式编程模型,你的控制器方法返回的 Flux<Test> 只是一个未被订阅的数据流定义,此时业务逻辑(比如 service.addCars() 里的操作)还没有实际执行——反应式流只有在被订阅后才会触发真正的计算。而 @AfterReturning 切面是在控制器方法返回对象的瞬间就触发了,自然拿不到实际的响应 payload,只会捕获到空的数据流容器。
解决方案
下面是两种实用的解决方式:
方案1:用 WebFilter 全局拦截响应
WebFilter 可以在响应写入客户端的前后处理内容,适合做全局的响应日志:
@Component public class ResponseLoggingFilter implements WebFilter { private static final Logger log = LoggerFactory.getLogger(ResponseLoggingFilter.class); @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpResponse originalResponse = exchange.getResponse(); DataBufferFactory bufferFactory = originalResponse.bufferFactory(); // 包装响应对象,捕获输出内容 ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { if (body instanceof Flux) { Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body; return super.writeWith(fluxBody.doOnNext(dataBuffer -> { // 读取响应字节并转换为字符串 byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); DataBufferUtils.release(dataBuffer); String responsePayload = new String(content, StandardCharsets.UTF_8); log.info("response :: {}", responsePayload); })); } return super.writeWith(body); } }; return chain.filter(exchange.mutate().response(decoratedResponse).build()); } }
方案2:修改切面为 @Around,订阅反应式流
如果必须用切面实现,可以用 @Around 环绕通知,在拿到返回的 Mono/Flux 后,通过反应式操作符在数据流产生元素时记录:
@Aspect @Component public class ResponseLoggingAspect { private static final Logger log = LoggerFactory.getLogger(ResponseLoggingAspect.class); @Around("pointCut()") public Object logResponse(ProceedingJoinPoint joinPoint) throws Throwable { Object result = joinPoint.proceed(); // 针对反应式类型添加日志逻辑 if (result instanceof Flux) { return ((Flux<?>) result).doOnNext(respValue -> { log.info("response :: {}", respValue); }); } else if (result instanceof Mono) { return ((Mono<?>) result).doOnNext(respValue -> { log.info("response :: {}", respValue); }); } // 非反应式类型直接返回 return result; } }
注意事项
- 不要在切面中调用
block()方法,这会阻塞反应式线程,完全破坏 WebFlux 的非阻塞特性。 - 如果需要在整个数据流完成后记录(而非每个元素),可以替换
doOnNext为doOnComplete,但后者无法获取具体的响应元素。
内容的提问来源于stack exchange,提问作者rjc
相关产品推荐
相关产品推荐

