在实际开发场景中,我们需要对代码进行一些参数打印等,在发生异常时,可以通过入参和返回参数进行一些简单的错误定位等。但是,在每个方法下面打印,对代码的入侵性比较大,下面,提供一个日志aop的模板。
这里简单介绍一下AOP,AOP(面向切面编程)是一种编程范式,它允许开发人员在程序的不同部分(切面)中定义横切关注点,并将它们与应用程序的核心业务逻辑分离开来。AOP可以用来实现日志记录、性能监控、事务管理等横切关注点,从而提高代码的模块化和可维护性。在AOP中,切面是一组横切关注点的集合,它们可以在程序的不同部分进行重用,从而减少重复代码的编写。AOP技术通常与面向对象编程结合使用,以实现更灵活和可维护的软件系统。
AOP(面向切面编程)的主要组成部分包括:
切面(Aspect):切面是一组横切关注点的集合,它定义了在程序的不同部分中需要执行的操作。切面可以包括日志记录、性能监控、事务管理等横切关注点。
连接点(Join Point):连接点是在程序执行过程中可以插入切面的点。这些点可以是方法调用、异常处理、变量赋值等。
通知(Advice):通知是切面在特定连接点执行的操作。通知可以是前置通知(在连接点之前执行)、后置通知(在连接点之后执行)、环绕通知(在连接点之前和之后执行)、异常通知(在连接点抛出异常时执行)和最终通知(在连接点执行后执行)。
切点(Pointcut):切点定义了在程序中哪些连接点会被切面影响。它使用表达式来匹配连接点。
引入(Introduction):引入允许向现有的类添加新的方法或属性。
@Slf4j
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(* com.xxx.xxx.controller.*.*(..))")
public void pt() {
}
@Around(value = "pt()")
public Object around(ProceedingJoinPoint pjp) {
Object result = null;
try {
// 前置通知
long startTime = System.currentTimeMillis();
// 获取url信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String url = request.getRequestURL().toString();
String method = request.getMethod();
String ip = request.getRemoteAddr();
String c = pjp.getSignature().getDeclaringType().getName();
String m = pjp.getSignature().getName();
String openId = request.getHeader("openId");
UserThreadLocal.putUser(openId);
// 进入方法前打印日志
log.info("请求信息 => url: [{}], method: [{}], ipAddress: [{}], className: [{}], methodName: [{}]", url, method, ip, c, m);
result = pjp.proceed();
// 后置通知
long endTime = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) pjp.getSignature();
String className = signature.getDeclaringType().getSimpleName();
String methodName = signature.getName();
Object[] args = pjp.getArgs();
StringBuilder sb = new StringBuilder();
sb.append(className)
.append(".")
.append(methodName)
.append("(");
for (int i = 0; i < args.length; i++) {
sb.append(args[i]);
if (i < args.length - 1) {
sb.append(",");
}
}
sb.append(")");
// 记录方法执行时间、参数和返回值
log.info("Method: {},Execution time: {}ms,Result: {}", sb, (endTime - startTime), result);
log.info("正在释放内存 openid: {}", UserThreadLocal.getUser());
UserThreadLocal.remove();
return result;
} catch (Throwable e) {
log.info("发生异常: {}", e.getMessage());
UserThreadLocal.remove();
}
return result;
}
}