When working on Spring MVC or Spring Boot applications, handling exceptions, data binding, or shared model attributes often ends up duplicated across controllers. That’s where @ControllerAdvice
comes in—a powerful annotation that helps you centralize behavior across all controllers. In this post, I’ll explain what @ControllerAdvice
does, how it works, and how I’ve used it to clean up real-world codebases.
🚀 What Is @ControllerAdvice
?
@ControllerAdvice
is a special Spring annotation that enables you to apply cross-cutting logic globally to all controllers. It works much like @Component
, so Spring auto-detects it during component scanning ([cite]turn0search0[/cite]).
Within a class annotated with @ControllerAdvice
, you can define:
@ExceptionHandler
methods to handle exceptions across all controllers@InitBinder
methods to customize how request data is converted and bound@ModelAttribute
methods to inject shared data into every model
This drastically reduces code duplication and improves maintainability. Instead of repeating @ExceptionHandler
in multiple controllers, you handle exceptions in one spot.
🔄 How @ControllerAdvice
Works
Spring internally uses the ExceptionHandlerExceptionResolver
to route exceptions to applicable handlers. When an exception is thrown in any controller:
- Spring looks for if a handler method exists locally (in that controller).
- If not found, it searches in
@ControllerAdvice
classes. - When found, the shared handler processes the exception and sends a clean response.
The same happens for @InitBinder
and @ModelAttribute
.
🎯 Pro Tips: Using @RestControllerAdvice
If you’re writing REST APIs and want controllers to return JSON error responses, use @RestControllerAdvice
instead. This variant combines @ControllerAdvice
with @ResponseBody
, so your global exception handler methods serialize errors as JSON automatically—perfect for REST‑oriented applications ([cite]turn0search0[/cite]).
💡 My Experience: Cleaner Error Handling & Shared Data
In a microservices project, I once had five different controllers handling custom exceptions like UserNotFoundException
, ValidationException
, and AuthenticationException
. Each controller duplicated the same error-handling logic, leading to inconsistent behaviors and code bloat.
By consolidating these into a single @ControllerAdvice
:

I achieved:
- Consistent error structure
- Centralized logging and monitoring
- Easier maintenance—adding new exception handling no longer required retrofitting every controller
Beyond exceptions, I used @ModelAttribute
to inject common attributes like currentUser
into every view-based controller, and @InitBinder
to trim input strings and parse dates consistently across forms.
✅ Best Practices with @ControllerAdvice
- Scope it correctly: You can restrict advice to specific packages or controllers using
annotations
orbasePackages
attributes. - Avoid mixing concerns: Keep exception handling separate from model-binding logic when possible.
- Use
@RestControllerAdvice
for APIs: It automates JSON responses and reduces boilerplate. - Test thoroughly: Write unit tests against advice-level exception methods to ensure consistent behavior.
🧾 Summary: Why @ControllerAdvice
Matters
@ControllerAdvice
is essential for:
- Handling errors consistently across multiple controllers
- Injecting shared model data to support views
- Customizing data-binding in one place
I’ve found it invaluable for making Spring applications cleaner, easier to maintain, and scalable—especially in mediums or large codebases.