Spring AOP 自定义注解实现统一日志管理

D
dashi34 2025-02-02T14:03:14+08:00
0 0 197

引言:在日常开发中,经常需要记录系统的日志信息来帮助排查问题或进行统计分析。而在一个大型的项目中,往往有大量的接口和方法需要记录日志,这会导致代码冗余、维护困难等问题。为了解决这个问题,我们可以利用Spring AOP和自定义注解来实现统一的日志管理,节省代码量,提高开发效率。

什么是Spring AOP和自定义注解

Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架提供的一种面向切面编程的技术。使用Spring AOP可以将具有相似功能的方法或逻辑进行统一管理,减少代码冗余,提高系统的可维护性和可扩展性。

自定义注解是Java语言的一个特性,允许我们自定义一些元数据(Annotation),可以应用在类、方法、参数等各个层面。通过自定义注解,我们可以在代码中添加一些标记,以此来触发特定的行为。

实现步骤

步骤一:定义自定义注解

我们首先定义一个自定义注解@Log,用来标记需要记录日志的方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
    String value() default "";
}

步骤二:编写切面类

切面类是Spring AOP的核心,用来定义切入点和增强逻辑。我们创建一个LogAspect类,并在类上添加@Aspect注解,表示这是一个切面类。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Around("@annotation(log)")
    public Object around(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        logger.info("Entering method: {}.{}()", className, methodName);
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            logger.info("Exiting method: {}.{}(), execution time: {} ms", className, methodName, endTime - startTime);
            return result;
        } catch (Throwable throwable) {
            logger.error("Exception in method: {}.{}(), message: {}", className, methodName, throwable.getMessage());
            throw throwable;
        }
    }

    @AfterThrowing(pointcut = "@annotation(log)", throwing = "ex")
    public void afterThrowing(Log log, Throwable ex) {
        String methodName = log.value();
        if (methodName.isEmpty()) {
            methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
        }
        String className = ex.getStackTrace()[0].getClassName();
        logger.error("Exception in method: {}.{}(), message: {}", className, methodName, ex.getMessage());
    }

    @AfterReturning("execution(* com.example.*.*(..)) && @annotation(log)")
    public void afterReturning(Log log) {
        String methodName = log.value();
        if (methodName.isEmpty()) {
            methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
        }
        String className = Thread.currentThread().getStackTrace()[2].getClassName();
        logger.info("Method: {}.{}() executed successfully.", className, methodName);
    }
}

在上面的代码中,我们使用@Around注解来定义一个环绕通知,用来在目标方法执行前后打印日志信息。@AfterThrowing注解用于在目标方法抛出异常时打印日志,@AfterReturning注解用于目标方法执行成功后打印日志。

步骤三:添加Spring AOP配置

在Spring的配置文件中,添加以下配置信息来启用Spring AOP功能。

<bean id="logAspect" class="com.example.LogAspect"/>
<aop:aspectj-autoproxy/>

步骤四:使用自定义注解

在需要记录日志的方法上添加@Log注解即可。

import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Log("getUserById")
    public User getUserById(String id) {
        // 查询数据库
        return user;
    }
}

总结

通过使用Spring AOP和自定义注解,我们可以实现统一的日志管理,减少重复代码的书写量,提高系统的可维护性和可扩展性。同时,我们可以根据实际需求扩展切面类的功能,如记录请求参数、返回结果等。

在实际项目中,我们可以结合业务需求,进一步优化和扩展日志管理功能。希望本文能对大家的开发工作有所帮助。

参考资料:

  1. Spring官方文档 - AOP
  2. Java官方文档 - 注解

相似文章

    评论 (0)