如何让Spring@ControllerAdise与其他定制的Spring@Aspects一起工作?
我有一个使用@Aspect
的自定义记录器,我希望它总是在最后运行,这样无论控制器返回什么响应,它都会被记录到数据库中(所以我在这个方面放了一个@Order(1)
)。我还使用@ControllerAdvice
编写了一个错误处理程序,它使用自定义响应正文处理所有意外异常和返回500
,并且我希望记录器也记录这一点,因此我在其上放置了@Order(2)
,然而,放置@Order
注释看起来并不安排Spring方面和Spring ControllerAdility之间的顺序,那么我如何让错误处理程序始终在记录器之前运行?(当然,不需要将我的错误处理程序转到另一个Spring方面)
解决方案
我一直在寻找并调试您的主要问题。我没有找到你关于@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");
}
}
结果为:
现在已记录WebAdise句柄
现在已记录完成后的WebInterceptor
如果您需要记录请求,也可以查看以下内容:https://www.baeldung.com/spring-http-logging
以下是我找到的有关Order、Aspect和ControllerAdance的信息
你说得对,@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
,结果将为:
方面现在已记录
ControllerAdise现在已记录
但我发现了一些有趣的事情:如果您设置了一个切入点@After
@ControllerAdvice
,那么您的方面将在ControlerAdance:
@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");
}
}
它被执行2次。一个在控制器之后,另一个在建议之后。
方面现在已记录
ControllerAdise现在已记录
Aspects现在已记录
也许这可以满足您的需求,但我真的不认为这是一个优雅的解决方案...
仍需解决的事情:
- 找到优先于
Aspect
和ControllerAdvice
的方法
希望不管怎样,它都会有所帮助。如果我找到更好的,我会让你知道的。
相关文章