springboot-learning-example中的AOP应用:日志记录与性能监控
springboot-learning-example中的AOP应用:日志记录与性能监控
在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的核心目录结构:
- 控制器层:chapter-3-spring-boot-web/src/main/java/demo/springboot/web/(如
BookController.java) - 服务层:chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/service/(如
BookServiceImpl.java)
日志记录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);
}
}
代码位置参考
- 控制器示例:chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java(包含
getBookList、postBook等方法) - 服务层示例:chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/service/impl/BookServiceImpl.java(包含
insertByBook、findById等业务方法)
性能监控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-web和chapter-5-spring-boot-data-jpa模块添加AOP功能。 - 关键代码参考:BookController.java、BookServiceImpl.java。
扩展方向
- 事务管理:结合
@Transactional实现声明式事务。 - 权限控制:通过AOP拦截未授权请求。
- 分布式追踪:集成SkyWalking等工具,通过AOP传递追踪上下文。
通过AOP,springboot-learning-example项目实现了横切关注点的解耦,提升了代码复用性和可维护性。建议开发者在实际开发中灵活运用AOP,优化系统架构。
本文代码基于springboot-learning-example项目,完整示例可参考项目README.md。
更多推荐



所有评论(0)