由于我们在编写代码的时候往往需要输出一些日志来查看代码运行的过程,好来排除错误,优化代码等。
而现阶段输出日志的普遍方法就是通过添加@Sl4j来生成注解,这就导致需要在方法内部在编写日志输出语句,极为不美观而且复用性差
为此,我们可以用面向切面编程,编写一个日志生成注解,可以做到通过一个在方法上的注解实现日志生成的自动化,
编写一个注解和一个切面类
下面解释一下这个代码的具体含义
1、
指定这个注解的位置,
2、
环绕通知
@Around
作用:环绕通知,可以在目标方法执行前后进行自定义逻辑控制,还可以决定是否继续执行目标方法。
使用场景:适用于需要完全控制方法执行流程的场景,如性能监控、事务管理等。
下面在介绍一些面向切面编程常用的常用的注解
1. @Before
作用:在目标方法执行之前执行。
使用场景:适用于需要在方法调用前进行一些预处理操作,如参数验证、日志记录等。
2. @After
作用:在目标方法执行之后执行,无论方法是否抛出异常。
使用场景:适用于需要在方法调用后进行一些清理工作或日志记录。
获取注解信息解释入下图注释
方法结束需要调用这个方法。
最后两个类编写玩后要注入bean容器中
@Bean public ApiOperationLogAspect apiOperationLogAspect() { return new ApiOperationLogAspect(); }
具体代码如下
public @interface ApiOperationLog {
/**
* API 功能描述
*
* @return
*/
String description() default "";
}
@Aspect
@Slf4j
public class ApiOperationLogAspect {
/** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */
@Pointcut("@annotation(com.cjm.framework.biz.operationlog.ApiOperationLog)")
public void apiOperationLog() {}
/**
* 环绕
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("apiOperationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 请求开始时间
long startTime = System.currentTimeMillis();
// 获取被请求的类和方法
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
// 请求入参
Object[] args = joinPoint.getArgs();
// 入参转 JSON 字符串
String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", "));
// 功能描述信息
String description = getApiOperationLogDescription(joinPoint);
// 打印请求相关参数
log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
description, argsJsonStr, className, methodName);
// 执行切点方法
Object result = joinPoint.proceed();
// 执行耗时
long executionTime = System.currentTimeMillis() - startTime;
// 打印出参等相关信息
log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
description, executionTime, JsonUtils.toJsonString(result));
return result;
}
/**
* 获取注解的描述信息
* @param joinPoint
* @return
*/
private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {
// 1. 从 ProceedingJoinPoint 获取 MethodSignature
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 2. 使用 MethodSignature 获取当前被注解的 Method
Method method = signature.getMethod();
// 3. 从 Method 中提取 LogExecution 注解
ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
// 4. 从 LogExecution 注解中获取 description 属性
return apiOperationLog.description();
}
/**
* 转 JSON 字符串
* @return
*/
private Function<Object, String> toJsonStr() {
return JsonUtils::toJsonString;
}
}