springboot-learning-example中的AOP应用:日志记录与性能监控

【免费下载链接】springboot-learning-example spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 【免费下载链接】springboot-learning-example 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-learning-example

在Spring Boot开发中,面向切面编程(AOP,Aspect-Oriented Programming)是一种强大的编程范式,它允许开发者在不修改业务逻辑代码的情况下,通过预定义的切入点(Pointcut)和通知(Advice)来实现横切关注点(如日志记录、性能监控、事务管理等)的复用。本文将以springboot-learning-example项目为基础,详细介绍如何通过AOP实现日志记录与性能监控功能,并结合项目中的实际代码结构进行讲解。

AOP核心概念与项目结构

AOP核心术语

  • 切面(Aspect):封装横切关注点的类,包含切入点和通知的定义。
  • 切入点(Pointcut):通过表达式定义哪些方法需要被增强。
  • 通知(Advice):定义在切入点执行的具体操作,包括前置通知(@Before)、后置通知(@After)、环绕通知(@Around)等。

项目AOP相关模块

springboot-learning-example中,AOP功能通常与业务模块结合实现。以下是项目中可能涉及AOP的核心目录结构:

日志记录AOP实现

场景需求

对所有控制器(Controller)的请求进行日志记录,包括请求URL、参数、响应结果和执行时间。

实现步骤

1. 定义切面类

创建LogAspect.java,使用@Aspect注解标记为切面,并通过@Pointcut定义切入点表达式,匹配所有控制器方法:

@Aspect
@Component
public class LogAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    // 切入点:匹配所有Controller中的public方法
    @Pointcut("execution(public * demo.springboot.web.*Controller.*(..))")
    public void controllerLog() {}

    // 前置通知:记录请求信息
    @Before("controllerLog()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        
        // 记录请求URL、方法、IP、参数
        logger.info("URL: " + request.getRequestURL().toString());
        logger.info("Method: " + request.getMethod());
        logger.info("IP: " + request.getRemoteAddr());
        logger.info("Args: " + Arrays.toString(joinPoint.getArgs()));
    }

    // 后置通知:记录响应结果
    @AfterReturning(returning = "result", pointcut = "controllerLog()")
    public void doAfterReturning(Object result) {
        logger.info("Response: " + result);
    }
}
2. 启用AOP自动代理

在Spring Boot主类中添加@EnableAspectJAutoProxy注解:

@SpringBootApplication
@EnableAspectJAutoProxy
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

代码位置参考

性能监控AOP实现

场景需求

对服务层(Service)的方法执行时间进行监控,当方法执行超时(如超过500ms)时发出告警日志。

实现步骤

1. 定义性能监控切面

创建PerformanceAspect.java,使用环绕通知(@Around)计算方法执行时间:

@Aspect
@Component
public class PerformanceAspect {
    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);
    private static final long TIME_THRESHOLD = 500; // 超时阈值(毫秒)

    // 切入点:匹配所有ServiceImpl类的方法
    @Pointcut("execution(* demo.springboot.service.impl.*ServiceImpl.*(..))")
    public void servicePerformance() {}

    // 环绕通知:计算执行时间
    @Around("servicePerformance()")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 执行目标方法
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;

        // 记录执行时间,超时则告警
        String methodName = joinPoint.getSignature().getName();
        if (costTime > TIME_THRESHOLD) {
            logger.warn("Performance Warning: Method [{}] took {}ms (exceeds {}ms)", 
                        methodName, costTime, TIME_THRESHOLD);
        } else {
            logger.info("Method [{}] executed in {}ms", methodName, costTime);
        }
        return result;
    }
}
2. 应用效果

当调用BookServiceImpl.insertByBook()方法时,AOP会自动计算执行时间并输出日志:

INFO  Method [insertByBook] executed in 120ms
WARN  Performance Warning: Method [findById] took 650ms (exceeds 500ms)

AOP通知类型与执行顺序

通知类型对比

通知类型 注解 执行时机 应用场景
前置通知 @Before 目标方法执行前 请求参数校验、日志记录
后置通知 @After 目标方法执行后(无论是否异常) 资源释放
返回通知 @AfterReturning 目标方法正常返回后 响应结果处理
异常通知 @AfterThrowing 目标方法抛出异常后 异常处理、告警
环绕通知 @Around 目标方法执行前后均可干预 性能监控、缓存

多切面执行顺序

当多个切面作用于同一方法时,可通过@Order注解指定优先级(值越小优先级越高):

@Aspect
@Component
@Order(1) // 优先级高于@Order(2)的切面
public class LogAspect { ... }

@Aspect
@Component
@Order(2)
public class PerformanceAspect { ... }

项目AOP最佳实践

1. 切入点表达式优化

  • 精确匹配:避免使用execution(* *(..))等过于宽泛的表达式,应限定具体包路径,如:
    // 仅匹配Controller中的GET请求方法
    @Pointcut("execution(public * demo.springboot.web.*Controller.get*(..))")
    

2. 避免AOP滥用

  • 仅对通用横切功能使用AOP(如日志、监控),业务逻辑应直接写在Service层。

3. 结合自定义注解

通过自定义注解(如@Loggable)实现更灵活的AOP控制:

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

// 在需要记录日志的方法上添加注解
@Loggable
public Book findById(Long id) { ... }

// 切入点改为注解匹配
@Pointcut("@annotation(demo.springboot.annotation.Loggable)")
public void annotationLog() {}

总结与扩展

本文核心要点

  • AOP通过切面和通知实现日志记录与性能监控,无需侵入业务代码。
  • springboot-learning-example中可通过扩展chapter-3-spring-boot-webchapter-5-spring-boot-data-jpa模块添加AOP功能。
  • 关键代码参考:BookController.javaBookServiceImpl.java

扩展方向

  • 事务管理:结合@Transactional实现声明式事务。
  • 权限控制:通过AOP拦截未授权请求。
  • 分布式追踪:集成SkyWalking等工具,通过AOP传递追踪上下文。

通过AOP,springboot-learning-example项目实现了横切关注点的解耦,提升了代码复用性和可维护性。建议开发者在实际开发中灵活运用AOP,优化系统架构。

本文代码基于springboot-learning-example项目,完整示例可参考项目README.md

【免费下载链接】springboot-learning-example spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 【免费下载链接】springboot-learning-example 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-learning-example

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐