工厂流水线全景:当你的Controller方法返回一个User对象时,Spring就像拥有一支隐形的魔杖,悄然将其变为JSON响应。今天我们将拆解Spring的"响应变形工厂",揭示@ResponseBody背后的黑魔法,以及异步返回值处理的时空穿梭术!
public interface HandlerMethodReturnValueHandler {
// 确认是否支持该类型变形
boolean supportsReturnType(MethodParameter returnType);
// 执行变形魔法
void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception;
}
核心变形设备清单(Spring 5.3):
// RequestResponseBodyMethodProcessor核心片段
protected <T> void writeWithMessageConverters(T value,
MethodParameter returnType,
ServletServerHttpRequest inputMessage,
ServletServerHttpResponse outputMessage) {
// 1. 内容协商选择最佳转换器
MediaType selectedMediaType = selectMediaType(...);
// 2. 获取对应消息转换器
HttpMessageConverter<T> converter = selectConverter(...);
// 3. 执行实际转换
converter.write(value, selectedMediaType, outputMessage);
}
转换器选择三原则:
// 查看所有注册的转换器
@Autowired List<HttpMessageConverter<?>> converters;
@GetMapping("/debug/converters")
public String showConverters() {
return converters.stream()
.map(c -> c.getClass().getSimpleName())
.collect(Collectors.joining("
"));
}
// 输出示例:
// ByteArrayHttpMessageConverter
// StringHttpMessageConverter
// MappingJackson2HttpMessageConverter
@GetMapping("/async/order")
public DeferredResult<Order> asyncOrder() {
DeferredResult<Order> result = new DeferredResult<>();
forkJoinPool.submit(() -> {
Order order = orderService.create();
result.setResult(order); // 异步设置结果
});
return result; // 立即返回空响应
}
// Spring内部处理流程:
// 1. 识别DeferredResult类型
// 2. 保存AsyncWebRequest到上下文
// 3. 异步线程完成后触发结果处理
@Async
@GetMapping("/future/user")
public CompletableFuture<User> futureUser() {
return CompletableFuture.supplyAsync(() -> {
return userService.findComplexUser(); // 耗时操作
}, taskExecutor);
}
// 变形设备:DelegatingAsyncTaskExecutor + FutureAdapter
实现目标:创建@MarkdownBody注解,自动渲染Markdown为HTML
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MarkdownBody {
String cssClass() default "markdown-body";
}
public class MarkdownReturnValueHandler implements HandlerMethodReturnValueHandler {
private final MarkdownParser parser = new FlexmarkMarkdownParser();
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return returnType.hasMethodAnnotation(MarkdownBody.class);
}
@Override
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
// 1. 转换Markdown
String htmlContent = parser.parse((String) returnValue);
// 2. 添加CSS样式
MarkdownBody annotation = returnType.getMethodAnnotation(MarkdownBody.class);
String fullHtml = wrapWithStyle(htmlContent, annotation.cssClass());
// 3. 写入响应
ServletWebResponse response = (ServletWebResponse) webRequest.getNativeResponse();
response.getServletResponse().setContentType("text/html");
response.getServletResponse().getWriter().write(fullHtml);
// 4. 标记处理完成
mavContainer.setRequestHandled(true);
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(0, new MarkdownReturnValueHandler());
}
}
@GetMapping("/docs/api")
@MarkdownBody(cssClass = "github-markdown")
public String getApiDoc() {
return "## API 文档\n" +
"`GET /users/{id}` 获取用户信息\n" +
"```java\n" +
"public class User { /*...*/ }\n" +
"```";
}
异常现象 | 常见原因 | 修复方案 |
---|---|---|
返回结果未转换 | 未注册对应转换器 | 检查HttpMessageConverter配置 |
异步响应超时 | DeferredResult未设置结果 | 增加超时回调处理 |
响应头被覆盖 | 多个处理器处理同一个返回值 | 调整处理器执行顺序 |
Content-Type不正确 | 未在处理器中正确设置 | 检查响应头设置代码 |
@GetMapping(value = "/smart",
produces = {MediaType.APPLICATION_JSON_VALUE, "text/markdown"})
public Object smartResponse() {
return new ResponseEntity<>(data, determineBestMediaType());
}
private HttpHeaders determineBestMediaType() {
// 根据请求头Accept选择最佳媒体类型
}
public class ResponseLoggingHandler implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler delegate;
public ResponseLoggingHandler(HandlerMethodReturnValueHandler delegate) {
this.delegate = delegate;
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return delegate.supportsReturnType(returnType);
}
@Override
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
log.info("处理返回值: {}", returnValue);
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
当掌握返回值处理的魔法后,你的控制器代码将获得以下超能力:
现在打开你的IDE,像魔法工程师一样定制Spring的响应处理流水线吧!记住,伟大的框架不是限制,而是等待你塑造的魔法黏土。当你的返回处理器足够灵活时,Web开发将如同施展魔法般优雅。