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
@ControllerAdviceand
@ExceptionHandler.
@ControllerAdviceworks as a global aspect for controllers. It can apply
@ExceptionHandler,
@InitBinder, and
@ModelAttributeto all or selected controllers, depending on its attributes.
@ExceptionHandlermarks a method that handles a specific exception type. The
valueattribute defines the exception class, and it can be combined with
@ResponseStatusto map to particular HTTP status codes.
Case Studies
Case 1 – Uniform Exception Structure
All APIs return the same error format. Create a
GeneralExceptionHandlerclass annotated with
@ControllerAdviceand define a method with
@ExceptionHandler(Exception.class)that builds a custom
MyErrorobject and returns a
ResponseEntity.
<code>@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()));
}
}
</code>Case 2 – Specific Exception for One Controller
For
OtherControllerwe can either add an
@ExceptionHandlermethod inside the controller or create a dedicated
@ControllerAdvicethat targets only this controller.
<code>@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()));
}
}
</code><code>@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()));
}
}
</code>Case 3 – Multiple Advice with Ordering
When two advice classes may handle the same exception, use
@Orderto define precedence. Without explicit ordering, Spring may pick one arbitrarily, leading to unpredictable behavior across different launch modes.
<code>@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()));
}
}
</code>Conclusion
These examples demonstrate how to implement most global exception‑handling scenarios in Spring Boot. Using
@RestControllerAdvicecan further simplify responses by automatically converting the returned object to JSON, eliminating the need to wrap it in
ResponseEntity.
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.