SpringMVC框架中的核心接口ResponseBodyAdvice

小豆丁 25天前 ⋅ 20 阅读

/**

  • Allows customizing the response after the execution of an {@code @ResponseBody}

  • or a {@code ResponseEntity} controller method but before the body is written

  • with an {@code HttpMessageConverter}.

  •  
  • <p>Implementations may be registered directly with

  • {@code RequestMappingHandlerAdapter} and {@code ExceptionHandlerExceptionResolver}

  • or more likely annotated with {@code @ControllerAdvice} in which case they

  • will be auto-detected by both.

  •  
  • @author Rossen Stoyanchev

  • @since 4.1

  • @param <T> the body type */ public interface ResponseBodyAdvice<T> {

    /**

    • Whether this component supports the given controller method return type
    • and the selected {@code HttpMessageConverter} type.
    • @param returnType the return type
    • @param converterType the selected converter type
    • @return {@code true} if {@link #beforeBodyWrite} should be invoked;
    • {@code false} otherwise */ boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);

    /**

    • Invoked after an {@code HttpMessageConverter} is selected and just before
    • its write method is invoked.
    • @param body the body to be written
    • @param returnType the return type of the controller method
    • @param selectedContentType the content type selected through content negotiation
    • @param selectedConverterType the converter type selected to write to the response
    • @param request the current request
    • @param response the current response
    • @return the body that was passed in or a modified (possibly new) instance */ @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);

} 解释一下,什么意思?

2025-10-09 13:37:48

这是一个 Spring MVC 框架中的核心接口 ResponseBodyAdvice&lt;T&gt;,它的主要目的是让你能够在控制器方法返回响应体(@ResponseBodyResponseEntity)之后、但在 HTTP 消息转换器(HttpMessageConverter)将响应体写入 HTTP 响应流之前,对响应体进行自定义处理。

核心功能:拦截并修改响应体

想象一下控制器方法执行完毕,它返回了一个对象(响应体)。Spring 会选择一个合适的 HttpMessageConverter(比如 MappingJackson2HttpMessageConverter 用于 JSON)来把这个对象转换成 HTTP 响应的字节流。ResponseBodyAdvice 就在这个转换发生之前介入,给你一个机会检查和修改这个响应体对象。

关键点解释:

  1. 触发时机:

    • 在控制器方法成功执行并返回一个 @ResponseBody 标记的返回值时。
    • 在控制器方法返回一个 ResponseEntity 对象时。
    • 选定的 HttpMessageConverter 调用其 write() 方法将响应体对象转换成字节流并写入 HTTP 响应之前
  2. 两个核心方法:

    • boolean supports(MethodParameter returnType, Class&lt;? extends HttpMessageConverter&lt;?&gt;&gt; converterType)
      • 作用: 判断这个 ResponseBodyAdvice 实现是否应该对当前请求的响应进行处理。
      • 参数:
        • returnType: 控制器方法的返回类型信息(包含方法本身、返回的泛型类型等)。
        • converterType: Spring 为当前响应选择的 HttpMessageConverter 的类型。
      • 返回值: true 表示这个 Advice 适用于当前响应,接下来会调用 beforeBodyWritefalse 表示不适用,跳过处理。
      • 应用场景: 你可以在这里根据控制器方法的返回类型(比如只处理某个特定类或注解标记的方法)、或者根据选定的消息转换器类型(比如只处理 JSON 响应)来决定是否启用处理逻辑。
    • @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class&lt;? extends HttpMessageConverter&lt;?&gt;&gt; selectedConverterType, ServerHttpRequest request, ServerHttpResponse response)
      • 作用: 这是实际执行响应体修改逻辑的地方。它在 supports 返回 true 后被调用。
      • 参数:
        • body: 控制器方法返回的原始响应体对象(可能为 null)。
        • returnType: 同上。
        • selectedContentType: 通过内容协商最终确定的响应的 Content-Type(如 application/json)。
        • selectedConverterType: 最终被选用来写入响应的 HttpMessageConverter 的类型。
        • request: 当前的 HTTP 请求对象。
        • response: 当前的 HTTP 响应对象(你可以在这里设置响应头等,但主要操作对象是 body)。
      • 返回值: 这个方法应该返回最终要写入 HTTP 响应的响应体对象。它可以是:
        • 原始的 body 对象(不做修改)。
        • 修改后的 body 对象(例如,添加字段、包装结构)。
        • 一个全新的对象(完全替换原始响应体)。
        • null(如果确实需要返回空响应体)。
      • 应用场景: 这是你实现自定义逻辑的核心位置。
  3. 注册方式:

    • 直接注册: 可以将你的 ResponseBodyAdvice 实现直接配置到 RequestMappingHandlerAdapterExceptionHandlerExceptionResolver 中(较少用)。
    • 自动检测(推荐): 更常见的是将你的实现类用 @ControllerAdvice(或 @RestControllerAdvice)注解标记。Spring 会自动扫描并注册这些类中的 ResponseBodyAdvice bean,使其对所有符合条件的控制器方法生效。这是实现全局响应处理的推荐方式。

典型应用场景:

  1. 统一响应包装: 这是最常见的用途。例如,你可能希望所有成功的 JSON 响应都被包装成一个标准结构:
    JSON
    {
      "code": 200,
      "message": "Success",
      "data": { ... } // 原始控制器返回的对象放在这里
    }
    
    beforeBodyWrite 中,你可以获取原始的 body(即 data 部分),创建一个新的 ResponseWrapper 对象(包含 code, message, data 属性),将原始 body 放入 data 中,然后返回这个 ResponseWrapper 对象。
  2. 全局响应日志: 记录即将返回给客户端的响应体内容(注意敏感信息过滤)。
  3. 响应体加密: 在将特定类型的数据发送给客户端前进行加密。
  4. 响应体压缩预处理(较少见): 在消息转换器处理前对数据进行特定处理(但通常压缩由其他机制处理)。
  5. 响应头设置: 虽然主要操作 body,但也可以通过传入的 response 参数设置一些基于响应体内容的响应头(但更常见的响应头设置可能在拦截器或控制器内完成)。
  6. 统一处理 null 响应: 将控制器返回的 null 转换成有意义的空对象表示。

总结:

ResponseBodyAdvice&lt;T&gt; 是 Spring MVC 提供的一个强大的扩展点,允许你在 HTTP 响应体被序列化并发送给客户端之前的最后时刻,对响应体进行拦截和修改。它通常与 @ControllerAdvice 结合使用,以实现全局性非侵入式的响应处理逻辑(如统一响应包装),极大地提高了代码的复用性和可维护性。它的工作流程由 supports 进行条件判断,由 beforeBodyWrite 执行具体的修改操作。

2025-10-09 13:38:08

Advice 是什么意思?

2025-10-09 13:56:58

在编程领域,尤其是 Spring 框架AOP(面向切面编程) 的上下文中,“Advice” 这个词有其特定的含义。它不是指日常生活中的“建议”,而是指在程序执行的特定时机插入的代码逻辑

你可以把它理解为:“增强”“通知”

核心概念:

想象程序执行就像一条直线(主流程)。AOP 允许你在某些特定的点(这些点称为 Join Point - 连接点,比如方法调用前、方法调用后、方法抛出异常时等)插入额外的代码。这些插入的代码片段就叫做 Advice(增强/通知)

ResponseBodyAdvice 中的具体含义:

  • ResponseBodyAdvice 这个接口的名字本身就体现了它的作用:它提供了一种机制,让你能够在响应体(Response Body)即将被写入 HTTP 响应流之前这个特定时机插入自定义的处理逻辑
  • 这里的 “Advice” 指的就是 beforeBodyWrite 方法里你编写的代码。这个方法就是 Spring 框架提供的一个“钩子”(hook),让你有机会在关键时刻“增强”或“通知”响应处理过程。
  • 它本质上是一种拦截器后处理器,作用于控制器方法返回响应体之后、消息转换器写入响应体之前这个环节。

类比理解:

  • 日常生活: 想象你要寄出一封信(主流程)。在把信投进邮筒(最终发送)之前,你可能会请一位顾问(Advisor)检查一下信的内容(Advice)。这位顾问可能会建议你修改措辞(修改响应体 body),或者加个附件(包装响应体),或者告诉你这封信根本不适合寄出(返回 null 或抛出异常)。ResponseBodyAdvice 就是 Spring 框架提供的这样一个“顾问”机制。
  • AOP 术语: 在 AOP 中,常见的 Advice 类型有:
    • Before advice: 在连接点(如方法调用)之前执行。
    • After returning advice: 在连接点成功完成之后执行(方法正常返回)。
    • After throwing advice: 在连接点抛出异常后执行。
    • After (finally) advice: 无论连接点如何结束(正常返回或异常)之后执行。
    • Around advice: 环绕连接点执行,可以在方法调用前后都加入逻辑,甚至可以控制是否执行原方法。
    • ResponseBodyAdvicebeforeBodyWrite 方法类似于一种特殊的 Around advice,它环绕着“将响应体对象写入 HTTP 响应流”这个动作。

总结:

ResponseBodyAdvice 以及 Spring AOP 中,“Advice” 指的是:

  1. 一段代码: 在程序执行的特定时机(连接点)被自动执行的代码块。
  2. 一种增强: 用于修改、扩展或补充程序核心流程(如响应处理)的行为。
  3. 一种通知: 它“通知”框架在某个点执行你的自定义逻辑。

因此,ResponseBodyAdvice 接口的作用就是:提供一个在响应体写入响应流之前执行自定义逻辑(Advice)的扩展点。 它的名字非常贴切地反映了它的功能。其他类似的接口如 RequestBodyAdvice 也是同样的命名逻辑。

2025-10-09 13:57:14

全部评论: 0

    我有话说: