Global Exception Handling in Spring Boot: History, Classification, and Implementation
This article explains how to replace repetitive try‑catch‑finally blocks with a unified global exception handling mechanism in Spring Boot, covering its evolution since Spring 3.x, classification of exceptions, the exact matching order, and a complete code example for developers.
Introduction
During software development, developers constantly encounter bugs and exceptions. The article demonstrates how to eliminate the clutter of repetitive try{...}catch{...}finally{...} blocks by adopting a unified global exception handling approach in Spring Boot.
Spring Boot Version
The examples are based on Spring Boot 2.3.4.RELEASE.
History of Global Exception Handling
Since Spring 3.x, the @ControllerAdvice annotation was introduced and can be used together with @ExceptionHandler, @InitBinder, @ModelAttribute, etc. Among these, @ExceptionHandler is directly related to exception processing and represents an "exception handler".
Exception handling can be divided into two categories: local exception handling and global exception handling.
Local Exception Handling
Local handling relies on @ExceptionHandler combined with @Controller. It only catches exceptions thrown from the specific controller where it is defined, which becomes impractical when an application has dozens or hundreds of controllers.
Global Exception Handling
To address the limitations of local handling, @ControllerAdvice (or @RestControllerAdvice) was created. By annotating a class with these and using @ExceptionHandler, developers can handle exceptions across all controllers. @RestControllerAdvice is essentially @ControllerAdvice plus @ResponseBody.
Classification of Spring Boot Exceptions
Exceptions are classified based on the controller entry point:
Pre‑controller exceptions (e.g., javax.servlet.ServletException) such as: NoHandlerFoundException – results in a 404 error when no matching controller is found. HttpRequestMethodNotSupportedException – thrown when the HTTP method does not match any controller method. HttpMediaTypeNotSupportedException – occurs when the request's Content‑Type is not supported (e.g., missing application/json for a @RequestBody parameter). MissingPathVariableException – raised when a required @PathVariable is absent in the URL.
Business‑layer exceptions – custom exceptions thrown from service or domain logic.
How to Implement Unified Exception Handling
Steps (using a front‑end/back‑end separated project as an example):
Create a class dedicated to global exception handling.
Annotate the class with @RestControllerAdvice (or both @ControllerAdvice and @ResponseBody).
On each method, add @ExceptionHandler and specify the exception types to capture (multiple exceptions can be listed).
Example implementation:
/**
* Global unified exception handling, simple configuration; customize further according to business needs.
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* Handles repeat‑submit exceptions.
*/
@ExceptionHandler(RepeatSubmitException.class)
public ResultResponse onException(RepeatSubmitException ex) {
log.error(ex.getMessage());
// TODO: log to database, etc.
return new ResultResponse(ResultCodeEnum.CODE_NOT_REPEAT_SUBMIT);
}
/**
* Handles custom business exceptions.
*/
@ExceptionHandler(ServiceException.class)
public ResultResponse onException(ServiceException ex) {
log.error(ex.getMessage());
// TODO: log to database, etc.
return new ResultResponse(ResultCodeEnum.CODE_SERVICE_FAIL);
}
/**
* Handles various pre‑controller exceptions (4xx status codes may be normalized to 200).
*/
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MissingServletRequestPartException.class,
BindException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class
})
public ResultResponse onException(Exception ex) {
log.error(ex.getMessage());
// TODO: log to database, etc.
return new ResultResponse(ResultCodeEnum.CODE_FAIL);
}
}In real projects, additional exceptions such as token expiration, Shiro, Spring Security, etc., should also be captured.
Exception Matching Order
If both a parent exception (e.g., Exception) and a child exception (e.g., ServiceException) have handlers, Spring selects the most specific one. The source code of ExceptionHandlerMethodResolver#getMappedMethod shows that it builds a list of candidate exception types, sorts them by depth using ExceptionDepthComparator, and picks the first (the closest match).
@Nullable
private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
List<Class<? extends Throwable>> matches = new ArrayList<>();
// iterate over declared exception types
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
if (mappedException.isAssignableFrom(exceptionType)) {
matches.add(mappedException);
}
}
if (!matches.isEmpty()) {
matches.sort(new ExceptionDepthComparator(exceptionType));
return this.mappedMethods.get(matches.get(0));
} else {
return null;
}
}The comparator recursively calculates the inheritance depth; a smaller depth means a more precise match.
Conclusion
Global exception handling is essential for clean, maintainable Spring Boot applications. By leveraging @ControllerAdvice / @RestControllerAdvice and precise exception matching, developers can centralize error responses, reduce boilerplate code, and improve overall system robustness.
Follow the author for more original content and consider the accompanying PDF book on MyBatis advanced topics.
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.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.
