Master Global Exception Handling in Spring Boot with @ControllerAdvice
This article explains how to use Spring Boot's @ControllerAdvice and @ExceptionHandler annotations to implement clean, global exception handling, covering basic usage, controller‑specific handlers, and ordered advice for multiple handlers, with practical code examples and diagrams.
Preface
When developing APIs, uncaught exceptions often appear. Adding a simple try...catch at the outermost layer works but quickly becomes messy if applied to every controller method. Using Aspect‑Oriented Programming (AOP) with Spring Boot provides a cleaner solution.
Main Annotations
The two key annotations are @ControllerAdvice and @ExceptionHandler. @ControllerAdvice works as a global aspect for controllers. It can apply @ExceptionHandler, @InitBinder, and @ModelAttribute to all or selected controllers, depending on its attributes. @ExceptionHandler marks a method that handles a specific exception type. The value attribute defines the exception class, and it can be combined with @ResponseStatus to map to particular HTTP status codes.
Case Studies
Case 1 – Uniform Exception Structure
All APIs return the same error format. Create a GeneralExceptionHandler class annotated with @ControllerAdvice and define a method with @ExceptionHandler(Exception.class) that builds a custom MyError object and returns a ResponseEntity.
@ControllerAdvice
public class GeneralExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity<Error> handleException(Exception ex) {
MyError myError = MyError.builder()
.text(ex.getMessage())
.code(ex.getErrorCode())
.build();
return new ResponseEntity(myError, HttpStatus.valueOf(ex.getErrorCode()));
}
}Case 2 – Specific Exception for One Controller
For OtherController we can either add an @ExceptionHandler method inside the controller or create a dedicated @ControllerAdvice that targets only this controller.
@RestController
@RequestMapping("/other")
public class OtherController {
@ExceptionHandler(OtherException.class)
protected ResponseEntity<Error> handleException(OtherException ex) {
MyOtherError myOtherError = MyOtherError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode())
.build();
return new ResponseEntity(myOtherError, HttpStatus.valueOf(ex.getErrorCode()));
}
}@ControllerAdvice(assignableTypes = OtherController.class)
public class OtherExceptionHandler {
@ExceptionHandler(OtherException.class)
protected ResponseEntity<Error> handleException(OtherException ex) {
MyOtherError myOtherError = MyOtherError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode())
.build();
return new ResponseEntity(myOtherError, HttpStatus.valueOf(ex.getErrorCode()));
}
}Case 3 – Multiple Advice with Ordering
When two advice classes may handle the same exception, use @Order to define precedence. Without explicit ordering, Spring may pick one arbitrarily, leading to unpredictable behavior across different launch modes.
@ControllerAdvice
public class GeneralExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity<Error> handleException(Exception ex) {
MyError myError = MyError.builder()
.text(ex.getMessage())
.code(ex.getErrorCode())
.build();
return new ResponseEntity(myError, HttpStatus.valueOf(ex.getErrorCode()));
}
}
@ControllerAdvice(assignableTypes = OtherController.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OtherExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity<Error> handleException(Exception ex) {
MyError myError = MyError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode())
.build();
return new ResponseEntity(myError, HttpStatus.valueOf(ex.getErrorCode()));
}
}Conclusion
These examples demonstrate how to implement most global exception‑handling scenarios in Spring Boot. Using @RestControllerAdvice can further simplify responses by automatically converting the returned object to JSON, eliminating the need to wrap it in ResponseEntity.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
