Backend Development 6 min read

Mastering Global and Local Exception Handling with @ControllerAdvice in Spring

This guide explains how to use @ControllerAdvice and @RestControllerAdvice for unified exception handling in Spring, compares their behavior, demonstrates local versus global handling, and shows advanced filtering by annotation, controller class, or package with practical code examples.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Global and Local Exception Handling with @ControllerAdvice in Spring

When an exception occurs in a Spring application, you can use @ControllerAdvice or @RestControllerAdvice to handle it uniformly.

The difference is that @RestControllerAdvice implicitly adds @ResponseBody , causing the method return value to be written directly to the HTTP response body (as a string or JSON).

Method 1: Local Exception Handling inside a Controller

<code>@RestController
public class TestController {
    @GetMapping("/test/{id}")
    public Object test(@PathVariable Integer id) {
        if (id < 5) {
            throw new RuntimeException("运行时异常");
        }
        return "测试异常处理";
    }

    @ExceptionHandler
    public Object handle(Exception e) {
        return e.getMessage();
    }
}</code>

This @ExceptionHandler method is invoked only when an exception is thrown from the same controller. It does not affect other controllers, making it suitable for controller‑specific error handling.

Method 2: Global Exception Handling

<code>@RestControllerAdvice
public class TestControllerAdvice {
    @ExceptionHandler
    public Object handle(Exception e) {
        return "我是全局异常:" + e.getMessage();
    }
}</code>

Applying @RestControllerAdvice (or @ControllerAdvice) makes the handler apply to all controllers. However, if a controller already defines its own @ExceptionHandler, the local handler takes precedence and the global one will not be triggered.

Advanced Scenarios

1. Handle only controllers with a specific annotation

<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AppAnnotation {}

@RestController
@AppAnnotation
public class AnnotationController {
    @GetMapping("/an/get/{id}")
    public Object an(@PathVariable Integer id) {
        if (id < 10) {
            throw new RuntimeException("发生错误了");
        }
        return "自定义Annotation注解: " + id;
    }
}

@RestController
public class AnnotationController2 {
    @GetMapping("/an/get2/{id}")
    public Object an(@PathVariable Integer id) {
        if (id < 10) {
            throw new RuntimeException("2发生错误了");
        }
        return "自定义Annotation注解2: " + id;
    }
}

@RestControllerAdvice(annotations = {AppAnnotation.class})
public class AnnotationControllerAdvice {
    @ExceptionHandler
    public Object handle(Exception e) {
        return "特定注解全局异常:" + e.getMessage();
    }
}</code>

Only controllers annotated with @AppAnnotation will be processed by this advice.

2. Handle only a specific controller

<code>@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public Object get(@PathVariable Integer id) {
        if (id < 10) {
            throw new RuntimeException("用户ID错误");
        }
        return "Users";
    }
}

@RestController
public class PersonController {
    @GetMapping("/person/{id}")
    public Object get(@PathVariable Integer id) {
        if (id < 10) {
            throw new RuntimeException("Person ID错误");
        }
        return "Person";
    }
}

@RestControllerAdvice(assignableTypes = {UserController.class})
public class SpecificControllerAdvice {
    @ExceptionHandler
    public Object handle(Exception e) {
        return "指定Controller全局异常:" + e.getMessage();
    }
}</code>

The advice applies only to exceptions thrown from UserController; PersonController exceptions are not intercepted.

3. Handle controllers in a specific package

<code>@RestControllerAdvice(basePackages = {"com.pack.pkg1"})
public class PackageControllerAdvice {
    @ExceptionHandler
    public Object handle(Exception e) {
        return "指定包下的全局异常:" + e.getMessage();
    }
}</code>

Only controllers located in com.pack.pkg1 will be covered by this advice.

In summary, local exception handlers have higher priority than global ones, and Spring provides flexible attributes ( annotations , assignableTypes , basePackages ) to narrow the scope of global exception handling.

Parameters accepted by @ExceptionHandler methods (refer to the image above).

backendJavaSpringExceptionHandlingControllerAdvice
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.