1. 添加依赖
在 Maven 项目的 pom.xml
文件中添加 Spring AOP 的依赖:
<dependencies>
<!-- Spring Boot Starter AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
2. 创建切面类
创建一个切面类,用于定义日志记录和性能监控的逻辑。
日志记录切面
package com.example.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点,匹配 com.example.service 包下所有类的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getName();
System.out.println("Before: Calling method " + methodName + " in class " + className);
}
// 后置通知
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("After: Method " + methodName + " executed");
}
// 返回通知
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("AfterReturning: Method " + methodName + " returned with result: " + result);
}
// 异常通知
@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("AfterThrowing: Method " + methodName + " threw exception: " + ex.getMessage());
}
}
性能监控切面
package com.example.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.logging.Logger;
@Aspect
@Component
public class PerformanceMonitorAspect {
private static final Logger logger = Logger.getLogger(PerformanceMonitorAspect.class.getName());
// 定义切点,匹配 com.example.service 包下所有类的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 环绕通知
@Around("serviceMethods()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = pjp.proceed(); // 调用目标方法
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Method execution time: " + elapsedTime + " ms for method: " + pjp.getSignature().toShortString());
return result;
}
}
3. 创建服务类
创建一个简单的服务类,用于测试切面功能。
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public String doSomething() {
System.out.println("Executing doSomething method");
return "Result";
}
}
4. 创建控制器类
创建一个控制器类,用于触发服务类的方法调用。
package com.example.controller;
import com.example.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/do-something")
public String doSomething() {
return myService.doSomething();
}
}
5. 启动类
创建一个 Spring Boot 启动类,启动应用。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AopApplication {
public static void main(String[] args) {
SpringApplication.run(AopApplication.class, args);
}
}
6. 测试
启动 Spring Boot 应用后,访问 http://localhost:8080/do-something
,观察控制台输出。
输出示例
控制台输出类似以下内容:
Before: Calling method doSomething in class com.example.service.MyService
Executing doSomething method
AfterReturning: Method doSomething returned with result: Result
After: Method doSomething executed
Method execution time: 10 ms for method: doSomething()
说明
-
日志记录切面:
-
使用
@Before
、@After
、@AfterReturning
和@AfterThrowing
注解,分别在方法执行前后、返回后和抛出异常后记录日志。 -
JoinPoint
提供了方法的上下文信息,如方法名、目标对象等。
-
-
性能监控切面:
-
使用
@Around
注解,记录方法的执行时间。 -
ProceedingJoinPoint
允许我们手动调用目标方法,并在调用前后插入逻辑。
-
-
切点表达式:
-
execution(* com.example.service.*.*(..))
表示匹配com.example.service
包下所有类的所有方法。
-
-
Spring AOP 的动态代理:
-
Spring AOP 使用动态代理技术(JDK 动态代理或 CGLIB 代理)来创建代理对象。
-
代理对象会拦截目标方法的调用,并在调用前后执行切面逻辑。
-
通过以上代码,你可以轻松地在 Spring Boot 项目中使用 Spring AOP 实现日志记录、性能监控等功能,而无需修改业务逻辑代码。