spring webmvc请求处理流程中返回值处理是什么

发布时间:2021-10-19 17:30:02 作者:柒染
来源:亿速云 阅读:136
# Spring WebMVC请求处理流程中返回值处理机制深度解析

## 目录
1. [引言](#引言)
2. [Spring WebMVC请求处理流程概览](#spring-webmvc请求处理流程概览)
3. [返回值处理的核心组件](#返回值处理的核心组件)
4. [返回值处理流程详解](#返回值处理流程详解)
5. [常见返回值类型处理](#常见返回值类型处理)
6. [自定义返回值处理器](#自定义返回值处理器)
7. [性能优化与最佳实践](#性能优化与最佳实践)
8. [常见问题与解决方案](#常见问题与解决方案)
9. [总结](#总结)

## 引言

Spring WebMVC作为Java领域最流行的Web框架之一,其请求处理流程的精妙设计一直是开发者关注的焦点。在完整的请求处理链路中,返回值处理(Return Value Handling)作为控制器方法执行后的关键环节,直接影响着最终响应内容的生成与返回。本文将深入剖析Spring WebMVC框架中返回值处理的实现机制,揭示其背后的设计哲学和技术细节。

## Spring WebMVC请求处理流程概览

### 1.1 请求生命周期全景图
```mermaid
sequenceDiagram
    participant Client
    participant DispatcherServlet
    participant HandlerMapping
    participant HandlerAdapter
    participant Handler
    participant HandlerMethodReturnValueHandler
    participant ViewResolver
    participant View
    
    Client->>DispatcherServlet: HTTP Request
    DispatcherServlet->>HandlerMapping: 获取Handler
    HandlerMapping-->>DispatcherServlet: 返回HandlerExecutionChain
    DispatcherServlet->>HandlerAdapter: 获取HandlerAdapter
    HandlerAdapter-->>DispatcherServlet: 返回适配器
    DispatcherServlet->>HandlerAdapter: 调用Handler处理请求
    HandlerAdapter->>Handler: 执行处理方法
    Handler-->>HandlerAdapter: 返回原始结果
    HandlerAdapter->>HandlerMethodReturnValueHandler: 处理返回值
    HandlerMethodReturnValueHandler-->>HandlerAdapter: 生成ModelAndView
    HandlerAdapter-->>DispatcherServlet: 返回ModelAndView
    DispatcherServlet->>ViewResolver: 解析视图
    ViewResolver-->>DispatcherServlet: 返回View
    DispatcherServlet->>View: 渲染视图
    View-->>DispatcherServlet: 返回渲染结果
    DispatcherServlet-->>Client: HTTP Response

1.2 关键阶段说明

  1. 请求分发阶段:DispatcherServlet作为前端控制器接收所有请求
  2. 处理器映射阶段:HandlerMapping解析请求URL找到对应处理器
  3. 处理器适配阶段:HandlerAdapter适配不同处理器类型
  4. 返回值处理阶段:HandlerMethodReturnValueHandler处理控制器方法返回值
  5. 视图解析与渲染阶段:ViewResolver和View完成最终响应生成

返回值处理的核心组件

2.1 HandlerMethodReturnValueHandler接口体系

public interface HandlerMethodReturnValueHandler {
    // 判断是否支持给定返回类型
    boolean supportsReturnType(MethodParameter returnType);
    
    // 处理返回值
    void handleReturnValue(@Nullable Object returnValue, 
                         MethodParameter returnType,
                         ModelAndViewContainer mavContainer,
                         NativeWebRequest webRequest) throws Exception;
}

2.2 内置处理器实现类

处理器类 支持返回类型 处理逻辑
ModelAndViewMethodReturnValueHandler ModelAndView 直接提取模型和视图信息
ModelMethodProcessor Model 将模型数据添加到ModelAndViewContainer
ViewMethodReturnValueHandler View 设置视图对象到容器
HttpEntityMethodProcessor HttpEntity 处理响应头和状态码
RequestResponseBodyMethodProcessor @ResponseBody 使用消息转换器序列化响应体
ViewNameMethodReturnValueHandler String 将字符串解释为视图名称
MapMethodProcessor Map 将Map内容作为模型属性

2.3 HandlerMethodReturnValueHandlerComposite

组合模式实现的多处理器协调器:

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
    private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
    
    public void addHandler(HandlerMethodReturnValueHandler handler) {
        this.returnValueHandlers.add(handler);
    }
    
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return getReturnValueHandler(returnType) != null;
    }
    
    @Override
    public void handleReturnValue(/* 参数省略 */) throws Exception {
        HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
    
    private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
        // 遍历查找支持的处理程序
    }
}

返回值处理流程详解

3.1 处理时序图

sequenceDiagram
    participant H as HandlerAdapter
    participant C as HandlerMethodReturnValueHandlerComposite
    participant RH as RequestResponseBodyMethodProcessor
    participant MC as ModelAndViewContainer
    participant MW as MessageConverter
    
    H->>C: 处理返回值(returnValue, returnType)
    C->>C: 遍历注册的处理器
    C->>RH: supportsReturnType(returnType)?
    RH-->>C: true
    C->>RH: handleReturnValue(...)
    RH->>MC: 设置请求已处理标志
    RH->>MW: 选择合适消息转换器
    MW->>RH: 执行转换(对象->JSON/XML等)
    RH->>H: 返回处理结果

3.2 关键处理步骤

  1. 返回值类型判断阶段

    • 通过MethodParameter获取方法返回类型
    • 检查方法/类上的注解(如@ResponseBody)
    • 考虑泛型类型参数和响应封装类型
  2. 处理器选择阶段

    • 按注册顺序遍历处理器链
    • 首个supportsReturnType返回true的处理器被选中
    • 默认处理器顺序在RequestMappingHandlerAdapter中初始化
  3. 实际处理阶段

    • 对于视图类型:设置视图名称或视图对象
    • 对于响应体:配置HTTP头,调用消息转换器
    • 对于重定向:处理RedirectAttributes
    • 对于异步结果:启动DeferredResult处理
  4. 结果封装阶段

    • 设置ModelAndViewContainer的相应状态
    • 标记请求是否已完全处理
    • 必要时转换响应编码

3.3 核心源码分析

RequestMappingHandlerAdapter中的处理入口:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    // ...前置处理省略
    
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    
    // 后置处理生成ModelAndView
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

// ServletInvocableHandlerMethod中的关键方法
public void invokeAndHandle(ServletWebRequest webRequest,
    ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    
    // 设置返回状态码
    setResponseStatus(webRequest);
    
    // 返回值处理核心逻辑
    try {
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception ex) {
        // 异常处理
    }
}

常见返回值类型处理

4.1 视图类型返回值

4.1.1 字符串视图名

@GetMapping("/home")
public String home(Model model) {
    model.addAttribute("message", "Hello World");
    return "homeView";  // 由ViewNameMethodReturnValueHandler处理
}

处理流程: 1. 将”homeView”解析为逻辑视图名 2. 通过ViewResolver解析为具体View实现 3. 最终由InternalResourceView渲染JSP/Thymeleaf等模板

4.1.2 直接返回View对象

@GetMapping("/report")
public View generateReport() {
    return new AbstractPdfView() { /* 实现细节 */ };
}

特点: - 跳过视图解析器直接使用返回的View - 适合动态生成二进制内容(PDF/Excel等)

4.2 响应体类型返回值

4.2.1 @ResponseBody注解处理

@GetMapping("/user/{id}")
@ResponseBody
public User getUser(@PathVariable Long id) {
    return userService.findById(id);
}

处理机制: 1. RequestResponseBodyMethodProcessor检测注解 2. 根据Accept头选择消息转换器 3. 常见转换器: - MappingJackson2HttpMessageConverter(JSON) - GsonHttpMessageConverter - ByteArrayHttpMessageConverter

4.2.2 ResponseEntity精细控制

@PostMapping("/create")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
    User saved = userService.save(user);
    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(saved.getId())
            .toUri();
    return ResponseEntity.created(location).body(saved);
}

优势: - 可定制HTTP状态码 - 灵活设置响应头 - 支持ETag等高级特性

4.3 异步返回值

4.3.1 DeferredResult

@GetMapping("/async")
public DeferredResult<String> asyncTask() {
    DeferredResult<String> result = new DeferredResult<>(5000L);
    executorService.submit(() -> {
        Thread.sleep(3000);
        result.setResult("Async result");
    });
    return result;
}

特点: - 非阻塞线程处理 - 支持超时设置 - 适用于长时间任务

4.3.2 Callable

@GetMapping("/callable")
public Callable<String> callableTask() {
    return () -> {
        Thread.sleep(1000);
        return "Callable result";
    };
}

处理流程: 1. 立即释放容器线程 2. 任务在Spring管理的线程池执行 3. 完成后重新派发请求

4.4 特殊类型处理

4.4.1 void返回类型

@PostMapping("/update")
public void updateItem(Item item) {
    itemService.update(item);
}

处理规则: - 默认使用请求URL作为视图名 - 可通过ServletResponse直接输出 - 适合RESTful无内容响应(204 No Content)

4.4.2 模型属性自动处理

@ModelAttribute
public void populateModel(Model model) {
    model.addAttribute("serverTime", LocalDateTime.now());
}

特点: - 方法返回值自动添加到模型 - 支持@ModelAttribute注解方法 - 可与@ControllerAdvice配合实现全局模型

自定义返回值处理器

5.1 实现场景分析

典型应用场景: - 处理框架不支持的返回类型 - 统一封装响应格式 - 特殊内容协商需求 - 自定义序列化逻辑

5.2 完整实现示例

5.2.1 自定义返回类型

public class ExcelExportResult {
    private String fileName;
    private List<?> data;
    private Class<?> templateClass;
    
    // 构造方法和getter省略
}

5.2.2 实现处理器

public class ExcelReturnValueHandler implements HandlerMethodReturnValueHandler {
    
    private final ResourceLoader resourceLoader;
    
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return ExcelExportResult.class.equals(returnType.getParameterType());
    }
    
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        
        ExcelExportResult result = (ExcelExportResult) returnValue;
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        
        // 设置响应头
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", 
            "attachment; filename=" + URLEncoder.encode(result.getFileName(), "UTF-8"));
        
        // 使用模板引擎生成Excel
        try (OutputStream out = response.getOutputStream()) {
            ExcelGenerator.generate(result.getData(), 
                result.getTemplateClass(), out);
        }
        
        mavContainer.setRequestHandled(true);
    }
}

5.2.3 注册处理器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
        handlers.add(0, new ExcelReturnValueHandler(resourceLoader));
    }
}

5.3 高级定制技巧

  1. 处理顺序控制

    • 通过实现Ordered接口或使用@Order注解
    • 在addReturnValueHandlers中注意添加顺序
  2. 内容协商增强

    public boolean supportsReturnType(MethodParameter returnType) {
       return returnType.hasMethodAnnotation(ExcelExport.class);
    }
    
  3. 异常处理集成

    try {
       // 处理逻辑
    } catch (Exception ex) {
       throw new HandlerMethodExecutionException("Excel生成失败", ex);
    }
    

性能优化与最佳实践

6.1 处理器选择优化

优化策略: 1. 常用处理器前置

   // 在配置类中调整顺序
   @Override
   public void configureHandlerAdapter(HandlerAdapterConfigurer configurer) {
       configurer.setReturnValueHandlers(
           customHandler,
           new RequestResponseBodyMethodProcessor(messageConverters),
           // 其他处理器...
       );
   }
  1. 缓存supportsReturnType结果: “`java private final Map supportCache = new ConcurrentHashMap<>();

@Override public boolean supportsReturnType(MethodParameter returnType) { return supportCache.computeIfAbsent(returnType, rt -> /* 实际判断逻辑 */); }


### 6.2 消息转换优化

1. **合理配置转换器**:
   ```java
   @Override
   public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       converters.add(0, new ProtobufHttpMessageConverter());
       converters.add(1, new MappingJackson2HttpMessageConverter());
   }
  1. 启用缓冲

    # application.properties
    spring.servlet.multipart.enabled=true
    spring.servlet.multipart.location=/tmp
    
  2. 流式处理大响应

    @GetMapping("/large-data")
    public StreamingResponseBody streamData() {
       return outputStream -> {
           // 分块写入数据
       };
    }
    

6.3 异步处理优化

  1. 配置专用线程池

    @Configuration
    public class AsyncConfig implements AsyncConfigurer {
    
    
       @Override
       public Executor getAsyncExecutor() {
           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
           executor.setCorePoolSize(10);
           executor.setMaxPoolSize(50);
           executor.setQueueCapacity(100);
           executor.initialize();
           return executor;
       }
    }
    
  2. 超时全局配置

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
       configurer.setDefaultTimeout(30000);
    }
    
  3. 异步结果缓存

    @GetMapping("/cached-data")
    public DeferredResult<String> getCachedData() {
       DeferredResult<String> result = new DeferredResult<>();
       cache.getAsynchronously("key", (k, v) -> result.setResult(v));
       return result;
    }
    

常见问题与解决方案

7.1 处理器匹配问题

问题现象: - 返回类型未被预期处理器处理 - 出现HttpMediaTypeNotAcceptableException

解决方案: 1. 调试处理器链:

   @Autowired
   private RequestMappingHandlerAdapter handlerAdapter;
   
   @PostConstruct
   public void logReturnValueHandlers() {
       List<HandlerMethodReturnValueHandler> handlers = 
           handlerAdapter.getReturnValueHandlers();
       // 输出处理器列表
   }
  1. 检查内容协商:
    
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
       configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
    

7.2 循环引用问题

问题场景

@GetMapping("/user")
@ResponseBody
public User getUser() {
    User user = userService.findUser();
    // User中包含对Role的引用,Role又引回User
    return user; 
}

解决方案: 1. 使用@JsonIgnore:

   @Entity
   public class User {
       @ManyToOne
       @JsonIgnore
       private Role role;
   }
  1. 配置全局序列化:
    
    @Bean
    public MappingJackson2HttpMessageConverter jacksonConverter() {
       ObjectMapper mapper = new ObjectMapper();
       mapper.configure(SerializationFeature.FL_ON_EMPTY_BEANS, false);
       mapper.enable(SerializationFeature.INDENT_OUTPUT);
       return new MappingJackson2HttpMessageConverter(mapper);
    }
    

7.3 时区与格式问题

日期处理方案

@Configuration
public class DateTimeConfig {
    
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> {
            builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
            builder.serializers(new LocalDateTimeSerializer(
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        };
    }
}

7.4 跨域与响应头问题

全局CORS配置: “`java @Configuration public class CorsConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(Cors
推荐阅读:
  1. 图解 Spring:HTTP 请求的处理流程与机制【5】
  2. 图解 Spring:HTTP 请求的处理流程与机制【1】

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring

上一篇:关于Window的问题有哪些

下一篇:从Druid迁移到ClickHouse的原因有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》