Spring集成Jersey时,如何在HTTP响应处理完成后清除MDC?
解决方案:利用Jersey的CompletionCallback清理MDC
Jersey提供了CompletionCallback接口,专门用于在响应完全处理完成(包括Multipart响应的转换、写入客户端等所有操作)后执行回调逻辑,正好满足你延迟清理MDC的需求。
1. 接口级别的局部处理
直接在返回的Response对象上注册CompletionCallback,仅针对当前接口生效:
@Path("/status/{requestID}") @GET public Response getStatus(@PathParam("requestID") String requestId) { MDC.put("myRequestID", requestId); // 构建Multipart响应的逻辑 MultiPart multiPart = new MultiPart(); // 添加响应内容,比如文件、文本等 multiPart.bodyPart(new BodyPart("status content", MediaType.TEXT_PLAIN_TYPE)); Response response = Response.ok(multiPart).build(); // 注册响应完成回调,清理MDC response.register(new CompletionCallback() { @Override public void onComplete(Throwable throwable) { MDC.clear(); } }); return response; }
2. 全局统一处理(推荐)
如果需要所有接口自动处理MDC清理,可以通过全局过滤器结合CompletionCallback实现,避免重复代码:
步骤1:实现ContainerRequestFilter,请求进入时设置MDC
@Provider public class MdcRequestFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) throws IOException { String requestId = requestContext.getUriInfo().getPathParameters().getFirst("requestID"); if (requestId != null) { MDC.put("myRequestID", requestId); } // 注册全局的响应完成回调 requestContext.setProperty("mdcCleanup", new CompletionCallback() { @Override public void onComplete(Throwable throwable) { MDC.clear(); } }); } }
步骤2:实现ContainerResponseFilter,将全局回调绑定到每个响应
@Provider public class MdcResponseFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { CompletionCallback cleanupCallback = (CompletionCallback) requestContext.getProperty("mdcCleanup"); if (cleanupCallback != null && responseContext.getResponse() instanceof Response) { ((Response) responseContext.getResponse()).register(cleanupCallback); } } }
步骤3:注册过滤器到Jersey
确保过滤器被Jersey扫描到,或在Spring配置中手动注册:
@Configuration public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(MdcRequestFilter.class); register(MdcResponseFilter.class); // 扫描接口所在包 packages("your.package.name"); } }
注意事项
CompletionCallback的onComplete方法无论响应处理成功还是失败都会被调用,不会因异常导致MDC未清理。- 若接口使用异步响应(
AsyncResponse),同样可以通过asyncResponse.register(new CompletionCallback())的方式注册回调,逻辑一致。
内容的提问来源于stack exchange,提问作者user007
相关产品推荐
相关产品推荐

