解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题
一、前言
- 在实际业务场景中,我们通常会使用全局异常处理机制,也就是在业务代码发生异常的时候,拦截异常并进行统一的处理,然后以JSON格式返回给前端。
- 同时我们也会使用aop进行操作日志记录,在不发生异常时,可以使用四种advice方式记录操作日志:@Before(“”),@After(“”)、 @AfterReturning(“”)、 @Around(“”)。当发生异常时,使用@AfterThrowing(value = “”,throwing = “e”)进行日志记录。
二、问题
同时使用上述两种方式,可能出现某一种失效的场景。
三、失效场景
失效场景一: 如果采用前后端不分离架构,采用下属代码返回前端响应结果,如果统一异常处理执行顺序在@AfterThrowing之前,就会出现@AfterThrowing中不执行情况。前后端分离架构不会出现此问题。
String xRequestedWith = request.getHeader("x-requested-with");
if ("XMLHttpRequest".equals(xRequestedWith)) {
response.setContentType("application/plain;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write(CommUnityUtil.getjsONString(1, "服务器异常!"));
} else {
response.sendRedirect(request.getContextPath() + "/error");
}
解决方案:让AOP日志处理类实现Ordered 接口,并重写getOrder()方法,使其返回值为1,返回值越小,执行的顺序越靠前,使其执行顺序优先于全部异常处理类。
@Component
@Aspect
public class LogAspectTest implements Ordered {
@Override
public int getOrder() {
return 1;
}
@AfterThrowing(value = "pointcut()",throwing = "e")
public void afterThrowing(JoinPoint joinPoint,Exception e){
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println("className is : " + className + ". methodName is : " + methodName);
System.out.println("afterThrowing excute········" + e.getMessage());
e.printStackTrace();
}
}
失效场景二:如果使用了 @Around(“”),在执行 joinPoint.proceed()方法时,捕获了异常,会导致全局异常处理无法收到异常,因此失效。
@Around("pointcut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println("className is : " + className + ". methodName is : " + methodName);
System.out.println("around excute before ········");
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
System.out.println("我捕获了异常");
}
System.out.println("obj 对象: " + obj);
System.out.println("around excute after ········");
}
解决方案:不要进行异常捕获,或者捕获后重新抛出异常。
@Around("pointcut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println("className is : " + className + ". methodName is : " + methodName);
System.out.println("around excute before ········");
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
System.out.println("我捕获了异常");
throw new RuntimeException("执行失败",e);
}
System.out.println("obj 对象: " + obj);
System.out.println("around excute after ········");
}
4、测试全部代码
package com.nowcoder.community.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.WEB.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
@Aspect
public class LogAspectTest implements Ordered {
@Override
public int getOrder() {
return 1;
}
@Pointcut("execution(* com.nowcoder.community.controller.*.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void before(JoinPoint joinPoint){
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
System.out.println(String.fORMat("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
System.out.println("before excute········");
}
@After("pointcut()")
public void after(JoinPoint joinPoint){
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
System.out.println("after excute········");
}
@AfterReturning("pointcut()")
public void afterReturning(JoinPoint joinPoint){
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
System.out.println("afterReturning excute········");
}
@AfterThrowing(value = "pointcut()",throwing = "e")
public void afterThrowing(JoinPoint joinPoint,Exception e){
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s],请求失败原因: [%s]", ip,
requestURI, requestMethod,className,methodName,e.getMessage()+e.getCause()));
System.out.println("afterThrowing excute········" + e.getMessage());
e.printStackTrace();
}
@Around("pointcut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println("className is : " + className + ". methodName is : " + methodName);
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null){
return;
}
// 请求ip
String ip = attributes.getRequest().getRemoteHost();
// 请求路径
String requestURI = attributes.getRequest().getRequestURI();
// 请求方法
String requestMethod = attributes.getRequest().getMethod();
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
System.out.println("我捕获了异常");
throw new RuntimeException("执行失败",e);
}
System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,
requestMethod,className,methodName));
System.out.println("around excute after ········");
}
}
到此这篇关于解决SpringBoot全局异常处理与AOP日志处理中@AfterThrowing失效问题的文章就介绍到这了,更多相关Springboot @AfterThrowing失效内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
相关文章