Controller Advice

通常情况下,@ExceptionHandler@InitBinder@ModelAttribute 方法会应用于声明它们的 @Controller 类(或类层次结构)内。如果您想让这些方法应用范围更广(跨控制器),则可以将它们声明为用 @ControllerAdvice@RestControllerAdvice 注释的类中。

@ControllerAdvice 使用 @Component 进行注解,这意味着此类可以通过 component scanning 注册为 Spring bean。@RestControllerAdvice 是经过注解的合成注解,其中使用了 @ControllerAdvice@ResponseBody 进行注解,这实质上意味着 @ExceptionHandler 方法将通过消息转换(相对于视图解析或模板渲染)呈现到响应主体。

在启动时,@RequestMapping@ExceptionHandler 方法的基础设施类会检测用 @ControllerAdvice 注释的 Spring bean,然后在运行时应用其方法。全局 @ExceptionHandler 方法(来自 @ControllerAdvice)会在局部 @ExceptionHandler 方法(来自 @Controller)之后应用。相比之下,全局 @ModelAttribute@InitBinder 方法会在局部方法之前应用。

默认情况下,@ControllerAdvice 方法会应用于每个请求(即所有控制器),但是您可以通过使用注释上的属性缩小范围到控制器的一个子集,如下面的示例所示:

  • Java

  • Kotlin

// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = [RestController::class])
public class ExampleAdvice1 {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = [ControllerInterface::class, AbstractController::class])
public class ExampleAdvice3 {}

前一个示例中的选择器在运行时得到评估,如果使用广泛,可能会对性能产生负面影响。请参见 @ControllerAdvice javadoc 以获取更多详细信息。