简体   繁体   中英

What are the advantages of @ControllerAdvice over @ExceptionHandler or HandlerExceptionResolver for handling exceptions?

Spring 3.2 introduced @ControllerAdvice annotation for handling exceptions in a Spring MVC application. But prior to this version Spring had @ExceptionHandler or HandlerExceptionResolver to handling exceptions in a Spring MVC application. Then why Spring 3.2 introduced @ControllerAdvice annotation for handling exceptions? I strongly believe that Spring 3.2 introduced @ControllerAdvice annotation to address the limitations of @ExceptionHandler or HandlerExceptionResolver or make the exceptions handling more stronger .

Can any one explain the advantages of @ControllerAdvice over @ExceptionHandler or HandlerExceptionResolver for handling exceptions?

@ExceptionHandler

@ExceptionHandler works at the Controller level and it is only active for that particular Controller, not globally for the entire application.

HandlerExceptionResolver

This will resolve any exception thrown by the application. It is used to resolve standard Spring exceptions to their corresponding HTTP Status Codes . It does not have control over the body of the response, means it does not set anything to the body of the Response .It does map the status code on the response but the body is null .

@ControllerAdvice

@ControllerAdvice used for global error handling in the Spring MVC application.It also has full control over the body of the response and the status code.

A @ExceptionHandler is local to a controller : only exceptions from this controller is routed to his @ExceptionHandler

But a @ControllerAdvice is global : you can have a centralized way to handle exceptions, binding, etc. it applies to all the defined controller.

Here is the difference: If I need to configure the exception handling code then I need to use @ExceptionHandler annotation in my project which can be used in two diff.ways: 1)To use the annotation and handle the exception in the same controller locally in each controller class. for eg:

@RestController
public class WSExposingController{

@GetMapping("/getAllDetails/{/id}")
public UserDetails myMethod(@PathVariable int id){
UserDetails user = UserDetailsService.getUser(id);
return user;
}

//To handle the exceptions which are resulting from this controller, I can declare an exceptionHandler specifically in the same class

@ExceptionHandler(Exception.class)
public ResponseEntity handlerSameControllerExceptions(){
return new ResponseEntity(null,HttpStatus.INTERNAL_SERVER_ERROR);

}

}

2)If I create a new class which extends ResponseEntityExceptionHandler(SpringBoot class) and if I ANNOTATE IT WITH @ControllerAdvice then that class becomes globalexceptionhandler meaning to say that any exception which is resulting in any controller class can be handled here. And it can be present in any package in the same project.

@RestController
@ControllerAdvice
public class GlobalJavaExceptionHandler extends ResponseEntityExceptionHandler{

    @ExceptionHandler(Exception.class)
    public ResponseEntity handleDiffControllerExceptions(){
        return new ResponseEntity(null,HttpStatus.INTERNAL_SERVER_ERROR);
    }

If both are present in the code then the local with take precedence over the global one. Ideally the second option is a better one as we need not add the code in each and every controller class and this class with @ControllerAdvice can be a one stop solution for all the exceptions arising due to the code beginning from the controller to the dao throughout the length of the code.

@ExceptionHandler can be used at the local level or at the global level. Local level would mean using this annotation within the controller itself to handle the exceptions within that controller only. All error thrown by that controller would be caught by that @ExceptionHandler. But this would mean that if there is a similar exception in a different controller you would have to rewrite the corresponding code again in that controller again locally.

In order to prevent repeating this style of exception handling per controller we can write the @ExceptionHanlder at the global level with the help of another annotation called @ControllerAdvice.

@ControllerAdvice is not specific to the exception handling , its also used for handling property, validation or formatter bindings at the global level. @ControllerAdvice in the context of exception handling is just another way of doing exception handling at a global level using @Exceptionhandler annotation.

Now coming to the HandlerExceptionResolver - this is an interface at a more lower level. Spring provides 2 implementations of this:

  • ResponseStatusExceptionResolver :This supports the support the @ResponseStatus annotation
  • ExceptionHandlerExceptionResolver : This supports the @ExceptionHandler annotation

Example : So when you want to handle exceptions and choose an exception handling strategy you will need to think of choosing between using a local or global exception handling via the annotations. How you need to provide the HTTP status codes, how to wrap it in the @Response entity etc, how you want to redirect to handler pages , carry the data via flash attributes or get params etc etc. Or maybe skip the annotations and use the SimpleMappingExceptionResolver and start mapping the specific exceptions to the error handler page urls

Here we are not be considering the lower level underlying HandlerExceptionResolver at this stage since we are dealing with its implementation at a higher level and building the strategy based on these options.

With the above context to answer your query - @ControllerAdvice was not introduced for exception handling, it's a mechanism you can leverage to handle exceptions globally using the @ExceptionHandler. HandlerExceptionResolver is an interface whose implementation helps support the @ResponseStatus and the @Exceptionhandler annotations. Unless you want to handle the exceptions related to the MVC system because the Spring framework does not provide any proper exception handling. So if you need to hand;e issues related to incorrect @Requestmapping etc which would not be caught by a controller as it would not even reach it in the 1st place then an implementation of the HandlerExceptionResolver would be useful

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM