tl;dr
How can I define the order of custom aspects and the @ControllerAdvice
?
Detailed description
I want to decorate various methods (like normal REST-Calls or a @JmsListener
) with MDC information on controller-level.
The idea is: I, as a developer, don’t have to think about the MDC data in my controller-methods.
I want extra MDC-information (e.g. the userId) and I can be sure, that information will be correctly removed.
my aspect
@Aspect @Component @Order(LOWEST_PRECEDENCE) public class MdcSugar { @Pointcut("within(@MdcAwareController *)") // <- MdcAwareController is my annotation public void beanAnnotatedWithMdcAwareController() { // this pointcut identifies beans annotated with @MdcAwareController } @Pointcut("execution(public * *(..))") public void publicMethod() { // this pointcut identifies public methods } @Pointcut("publicMethod() && beanAnnotatedWithMdcAwareController()") public void publicMethodInsideMdcAwareController() { // this pointcut identifies public methods on beans annotated with @MdcAwareController } @Before("publicMethodInsideMdcAwareController()") public void addMdcSugar(JoinPoint joinPoint) { log.info("Entered"); MDC.put("test", "test"); } @After("publicMethodInsideMdcAwareController()") public void removeMdcSugar() { log.info("Leaved"); MDC.clear(); } }
example controller
@RestController @MdcAwareController // <- my annotation public class SomeController { // doesn't matter if the method is a JmsListener or something else @GetMapping("/{id}") public String get(@PathVariable String id) { MDC.put("id", id); log.info("Got request"); throw new RuntimeException("too bad ..."); } }
ControllerAdvice
@ControllerAdvice @Order(HIGHEST_PRECEDENCE) public class GeneralExceptionHandler extends ResponseEntityExceptionHandler { // some others cases with different handlers @ExceptionHandler(RuntimeException.class) protected ResponseEntity<HttpErrorResponseBody> handleUncaught(RuntimeException e) { log.error("Uncaught exception occurred", e); return new ResponseEntity<>(e.toString(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); } }
Now I have a problem when a exception occurs. My aspect will always clear the MDC-context before the exception-handler jumps in. Log example:
Entered
[test=test][id=someString] Got request
[test=test][id=someString] Leaved
Uncaught exception occurred
But I want something like this:
Entered
[test=test][id=someString] Got request
[test=test][id=someString] Uncaught exception occurred
[test=test][id=someString] Leaved
I already tried to place @Order()
on MdcSugar
and GeneralExceptionHandler
, but with no affect.
Advertisement
Answer
Sometimes the world is so easy – I only need to clear the MDC-data at the beginning.
@Aspect @Component public class MdcSugar { @Pointcut("within(@MdcAwareController *)") // <- MdcAwareController is my annotation public void beanAnnotatedWithMdcAwareController() { // this pointcut identifies beans annotated with @MdcAwareController } @Pointcut("execution(public * *(..))") public void publicMethod() { // this pointcut identifies public methods } @Pointcut("publicMethod() && beanAnnotatedWithMdcAwareController()") public void publicMethodInsideMdcAwareController() { // this pointcut identifies public methods on beans annotated with @MdcAwareController } @Before("publicMethodInsideMdcAwareController()") public void addMdcSugar(@Nullable JoinPoint joinPoint) { MDC.clear(); log.info("Entered"); MDC.put("test", "test"); } }