基于 Spring AOP (面向切面编程) 的切面类--自定义方法注解的方式打印日志

java每日一学 ---- 面向切面编程

怎么通过方法注解的方式打印日志呢?自定义注解

1、首先定义一个@ExecuteLog 注解类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecuteLog {

    /**
     * 执行方法的描述,默认方法名
     *
     * @return 描述
     */
    String value() default "";
    boolean includeRequest() default true;
    boolean includeResult() default true;
}

方法讲解:
(1)、@Target(ElementType.METHOD)

作用:指定该注解只能应用于方法上。 解释:@Target 注解表示自定义注解的作用范围。这里的 ElementType.METHOD
表示该注解只能应用于方法。

(2)、@Retention(RetentionPolicy.RUNTIME)

作用:指定注解的生命周期。 解释:@Retention 注解表示注解的存活时间。RUNTIME 表示注解在运行时有效,可以通过反射机制访问。

(3)、String value() default “”;

作用:定义一个字符串属性 value,默认为空字符串。 解释:这个属性用于给方法添加一个描述信息,默认情况下,value
为方法名。如果方法没有显式提供描述,value 默认将是方法的名字。

(4)、boolean includeRequest() default true;

作用:定义一个布尔属性 includeRequest,默认为 true。 解释:决定在日志中是否包括请求参数。如果为
true,会记录请求参数;如果为 false,则不记录请求参数。

(5)、boolean includeResult() default true;

作用:定义一个布尔属性 includeResult,默认为 true。 解释:决定在日志中是否包括方法执行结果。如果为
true,会记录方法的返回值;如果为 false,则不记录方法的返回值。

2、ExecuteLogAspect 切面类,再定义一个切面类

@Aspect
@Component
public class ExecuteLogAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExecuteLogAspect.class);

    @Around("@annotation(executeLog)")
    public Object recordIntervalLog(ProceedingJoinPoint pjp, ExecuteLog executeLog) throws Throwable {
        LocalDateTime beginTime = LocalDateTime.now();
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Object[] args = pjp.getArgs();
        Method method = signature.getMethod();
        String methodName = StringUtils.defaultIfBlank(executeLog.value(), method.getName());
        String processId = RandomUtils.getShortUUID();
        if (executeLog.includeRequest()) {
            LOGGER.info("start to process [{}], clientId [{}], userId [{}], params: [{}], startTime: [{}], processId: [{}]", methodName, AppContext.getClientId(), AppContext.getFineUid(), args, beginTime, processId);
        } else {
            LOGGER.info("start to process [{}], clientId [{}], userId [{}], startTime: [{}], processId: [{}]", methodName, AppContext.getClientId(), AppContext.getFineUid(), beginTime, processId);
        }
        Object result = pjp.proceed();
        LocalDateTime endTime = LocalDateTime.now();
        if (executeLog.includeResult()) {
            LOGGER.info("process[{}],Id: [{}] finished, result:[{}], endTime: [{}], costTime: [{}] ms", methodName, processId, result, endTime, beginTime.until(endTime, ChronoUnit.MILLIS));
        } else {
            LOGGER.info("process[{}],Id: [{}] finished, endTime: [{}], costTime: [{}] ms", methodName, processId, endTime, beginTime.until(endTime, ChronoUnit.MILLIS));
        }
        return result;
    }
}

(1)、@Aspect

作用:表示该类是一个切面类(Aspect)。 解释:@Aspect 是 AOP
编程中的关键注解,标记这个类为切面类,意味着这个类将包含切面逻辑,即方法执行前后做一些操作。

(2)、@Component

作用:表示该类是一个 Spring Bean。 解释:@Component 注解将这个类注册到 Spring 上下文中,Spring
容器会自动扫描并创建该类的实例,供其他组件使用。

(3)、@Around(“@annotation(executeLog)”)

作用:这是一个环绕通知,用来定义一个环绕方法。 解释:@Around 注解指定了一个切点,该切点是所有标注了 @ExecuteLog
注解的方法。通过 @annotation(executeLog),Spring 会将方法上注解的实例传递给方法参数 executeLog。

(4)、public Object recordIntervalLog(ProceedingJoinPoint pjp, ExecuteLog
executeLog) throws Throwable

作用:定义一个环绕通知方法。 解释:ProceedingJoinPoint
提供了对目标方法的控制,允许我们在方法执行前后做一些操作。ExecuteLog executeLog
用来接收目标方法上注解的实例,throws Throwable 表示该方法可能会抛出异常。

        LocalDateTime beginTime = LocalDateTime.now();
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Object[] args = pjp.getArgs();
        Method method = signature.getMethod();
        String methodName = StringUtils.defaultIfBlank(executeLog.value(), 
                                                         method.getName());
        String processId = RandomUtils.getShortUUID();

(5)、MethodSignature signature = (MethodSignature) pjp.getSignature();

作用:获取方法的签名信息。 解释:pjp.getSignature() 返回的是 MethodSignature
类型的对象,包含了方法的签名信息,MethodSignature 是 Signature 类的子类,提供了获取方法、参数类型等信息的方法。

(6)、Object[] args = pjp.getArgs();

作用:获取方法参数。 解释:pjp.getArgs() 获取目标方法的参数列表,供后续在日志中记录请求参数时使用。

(7)、Method method = signature.getMethod();

作用:获取目标方法的 Method 对象。 解释:signature.getMethod() 返回当前方法的 Method
对象,用来获取方法的详细信息。

(8)、String methodName = StringUtils.defaultIfBlank(executeLog.value(), method.getName());

作用:获取方法的名称,如果注解中 value 属性有设置,则使用该属性值,否则使用方法名。
解释:StringUtils.defaultIfBlank 会检查 executeLog.value()
是否为空或空白,如果是,则使用方法的名称 method.getName()。

(9)、Object result = pjp.proceed();

作用:执行目标方法。 解释:pjp.proceed() 调用目标方法并返回其结果。这里的 proceed() 是
ProceedingJoinPoint 提供的执行方法的 API。

3、 如何使用呢?

 @ExecuteLog
    fun getXXX(event: StreamStatusChangeEvent) {
    ....
    }

结果:

打印日志:start to process [setExtractPendingAfterStreamFinished], clientId
[null], userId [null], params:
[[StreamStatusChangeEvent(connectId=xxx, taskId=xx, pluginId=xxx,
tableId=xx, status=Complete, task=ConnectionTaskDO(id=xx,
fineUid=null, pluginId=11024, connectId=xx, config=null, state=null,
configuredCatalog=null, streamNames=null, attempts=null,
syncRecordStat=null, status=null, startedAt=null, syncEndAt=null,
finishedAt=null, fullSync=null, errorMsg=null, createdAt=null,
updatedAt=Fri Nov 22 10:00:24 CST 2024, deletedAt=null, groupId=null,
extractTasks=null))]], startTime: [2024-11-22T10:03:16.101050],
processId: [b1edd217]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值