我有一个使用@Aspect
的自定义记录器,希望它总是在最后运行,以便无论从控制器返回什么响应,它都将记录到数据库中(因此我在这方面放了@Order(1)
) 。而且我还使用@ControllerAdvice
编写了一个错误处理程序,该错误处理程序处理所有意外的异常并返回带有自定义响应正文的500
,我也希望记录器也记录此错误,因此我在其上放了@Order(2)
,但是,看起来像@Order
注释不能在Spring Aspect和Spring ControllerAdvice之间安排顺序,因此如何让我的错误处理程序始终在记录器之前运行? (当然,无需将错误处理程序转移到另一个Spring Aspect)]
我一直在寻找和调试您的主要问题。我没有找到您有关@Order
的问题的答案,但我会与您分享我的想法(本文的第二部分)
Interceptor
?它们提供了在进入控制器之前以及执行@ControllerAdvice
之后(如果有)记录操作的方式。
@Component
public class WebInterceptor extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(WebInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.error("WebInterceptor prehandle is now logged");
return super.preHandle(request, response, handler);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.error("WebInterceptor after completion is now logged");
super.afterCompletion(request, response, handler, ex);
}
}
要激活此拦截器,您需要创建一个新的@Configuration
类,并实现WebMvcConfigurer
:
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private WebInterceptor webInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(webInterceptor).addPathPatterns("/user");
}
}
我为测试创建了一个简单的Controller
和ControllerAdvice
:
@RestController
public class WebController {
@GetMapping("/user")
public String user() {
throw new IllegalArgumentException("my bad");
}
}
@RestControllerAdvice
@Order(2)
public class WebAdvice {
private Logger logger = LoggerFactory.getLogger(WebAdvice.class);
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void handle(RuntimeException e) {
logger.error("ControllerAdvice is now logged");
}
}
结果是:
现在已记录WebAdvice句柄完成后现在记录WebInterceptor]
如果您需要记录请求,也可以查看一下:https://www.baeldung.com/spring-http-logging
您是对的,@ControllerAdvice
和@Aspect
之间没有优先级,很好...
我无法找到原因(尚未),但是当@Aspect
指向@Controller
方法时,无论您设置的顺序如何,都将在@ControllerAdvice
之前执行切入点操作
@Aspect
@Component
@Order(1)
public class MyAspect {
private Logger logger = LoggerFactory.getLogger(MyAspect.class);
@After("execution(* WebController.user(..))")
public void afterLog() {
logger.error("Aspect is now logged");
}
}
@RestControllerAdvice
@Order(2)
public class WebAdvice {
private Logger logger = LoggerFactory.getLogger(WebAdvice.class);
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void handle(RuntimeException e) {
logger.error("ControllerAdvice is now logged");
}
}
如果您Get http://localhost:8080/user
,结果将是:
现在已记录方面现在已记录ControllerAdvice
但是我发现了一些有趣的事情:如果您将切入点设置为@After
和@ControllerAdvice
,则在controllerAdvice之后将执行该方面:
@Aspect
@Component
@Order(1)
public class MyAspect {
private Logger logger = LoggerFactory.getLogger(MyAspect.class);
@After("execution(* WebAdvice.handle(..)) || execution(* WebController.user(..))")
public void afterLog() {
logger.error("Aspect is now logged");
}
}
执行两次。一处在管制员之后,一处在建议之后。
现在已记录方面现在已记录ControllerAdvice现在已记录方面[]
也许这可以满足您的需求,但是我并不觉得这是一个优雅的解决方案...
仍需解决的问题:
Aspect
和ControllerAdvice
的方法希望无论如何都会有帮助。如果我发现更好的地方,我会通知您。