Spring Boot使用AOP做日志管理
程序员文章站
2022-04-25 19:37:47
...
package com.*******;
import com.**.dc.common.result.ResultObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.logging.Logger;
/**
* @author Ls.
* @date 2019/11/25 16:30
*/
@Aspect //Aspect注解代表是一个切面类
@Component //Component注解代表把此类交给spring来管理
public class LogAspect {
private static Logger logger = Logger.getLogger(String.valueOf(LogAspect.class));
/**
* 这句话是方法切入点
* 1 execution (* com.my.blog.website.controller..*.*(..))
* 2 execution : 表示执行
* 3 第一个*号 : 表示返回值类型, *可以是任意类型
* 4 com.my.blog.website.controller : 代表扫描的包
* 5 .. : 代表其底下的子包也进行拦截
* 6 第二个*号 : 代表对哪个类进行拦截,*代表所有类
* 7 第三个*号 : 代表方法 *代表任意方法
* 8 (..) : 代表方法的参数有无都可以
*
* 通知执行顺序:
* (1)没有异常(不会走异常通知)
* 前置通知->环绕通知之前部分->后置通知(异常不调用)->最终通知(异常也会调用)->环绕通知之后的部分
* (2)有异常(不会走环绕通知的后半部分和后置通知)
* 前置通知->环绕通知之前部分->最终通知(异常也会调用)->异常通知
*/
//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
@Pointcut("execution( * com.wangyuan.dc.gateway.controller..*.*(..))") //声明一个切入点
public void webLog(){}
//前置通知等可以没有JoinPoint参数 before方法执行之前做的事
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString()
+ ",IP : " + request.getRemoteAddr()
+ ",Method : " + request.getMethod()
+ ",CLASS_METHOD : "+ joinPoint.getSignature().getDeclaringTypeName()
+ "." + joinPoint.getSignature().getName()
+ ",ARGS : " + Arrays.toString(joinPoint.getArgs()));
}
//配置后置返回通知(异常发生后不会调用),使用在方法webLog()上注册的切入点
// @AfterReturning(returning = "object", pointcut = "webLog()")
// public void doAfterReturning(Object object) throws Throwable {
// // 处理完请求,返回内容
// logger.info("RESPONSE :" + object);
// }
@AfterReturning(returning = "resultObjectr", pointcut = "webLog()")
public void logResultVOInfo(ResultObject resultObjectr) throws Exception {
logger.info("请求结果:" + resultObjectr.getCode() + "\t" + resultObjectr.getMsg());
}
// 环绕通知(推荐下面这种方式获取方法)
@Around("webLog()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("----------------环绕通知之前 的部分(注解)----------------");
// 获取到类名
String targetName = pjp.getTarget().getClass().getName();
System.out.println("代理的类是:" + targetName);
// 获取到参数
Object[] parameter = pjp.getArgs();
System.out.println("传入的参数是:" + Arrays.toString(parameter));
// 获取到方法签名,进而获得方法
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
System.out.println("增强的方法名字是:" + method.getName());
// 获取参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.println("参数类型是:" + parameterTypes.toString());
//让方法执行(proceed是拦截的方法的执行返回值,可以针对返回值做一些处理)
System.out.println("--------------方法开始执行-----------------");
Object proceed = pjp.proceed();
//环绕通知之后的业务逻辑部分
System.out.println("----------------环绕通知之后的部分(注解)----------------");
return proceed;
}
// 异常通知
@AfterThrowing("webLog()")
public void afterException() {
System.out.println("这是异常通知(发生异常后调用)~~~~~~~~~~~(注解)");
}
// 最终通知(发生异常也会在最终调用)
@After("webLog()")
public void after() {
System.out.println("这是最终通知(发生异常也会在最终调用)........(注解)");
}
}
推荐阅读