一、AOP核心概念图解
二、注解驱动开发全流程
2.1 基础环境配置
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 启用CGLIB代理
@ComponentScan("com.example.aop")
public class AppConfig {
// 无XML配置模式
}
2.2 切面定义模板
@Aspect
@Component
public class LoggingAspect {
// 定义可重用的切点
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Pointcut("@annotation(com.example.annotation.Auditable)")
public void auditableMethod() {}
}
三、五大通知类型实现
3.1 前置通知(Before)
@Before("serviceLayer() && args(param)")
public void logBefore(JoinPoint jp, String param) {
MethodSignature signature = (MethodSignature) jp.getSignature();
System.out.printf("[前置通知] 方法 %s 参数: %s%n",
signature.getMethod().getName(), param);
}
3.2 后置通知(AfterReturning)
@AfterReturning(
pointcut = "serviceLayer()",
returning = "result"
)
public void logAfterReturning(JoinPoint jp, Object result) {
System.out.printf("[返回通知] 方法 %s 返回值: %s%n",
jp.getSignature().getName(), result);
}
3.3 异常通知(AfterThrowing)
@AfterThrowing(
pointcut = "serviceLayer()",
throwing = "ex"
)
public void logException(JoinPoint jp, Exception ex) {
System.out.printf("[异常通知] 方法 %s 抛出异常: %s%n",
jp.getSignature().getName(), ex.getMessage());
}
3.4 最终通知(After)
@After("serviceLayer()")
public void logFinally(JoinPoint jp) {
System.out.printf("[最终通知] 方法 %s 执行完成%n",
jp.getSignature().getName());
}
3.5 环绕通知(Around)
@Around("serviceLayer()")
public Object measurePerformance(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} finally {
long duration = System.currentTimeMillis() - start;
System.out.printf("[环绕通知] 方法 %s 执行耗时: %dms%n",
pjp.getSignature().getName(), duration);
}
}
四、高级切面编程技巧
4.1 自定义注解实现
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
String key() default "";
int ttl() default 300;
}
// 应用注解
@Aspect
@Component
public class CacheAspect {
@Around("@annotation(cacheable)")
public Object cacheResult(ProceedingJoinPoint pjp, Cacheable cacheable)
throws Throwable {
String key = generateCacheKey(pjp, cacheable);
Object result = cache.get(key);
if (result == null) {
result = pjp.proceed();
cache.put(key, result, cacheable.ttl());
}
return result;
}
}
4.2 多切面执行顺序控制
@Aspect
@Order(1) // 数字越小优先级越高
public class ValidationAspect {
@Before("serviceLayer()")
public void validateInputs(JoinPoint jp) {
// 参数校验逻辑
}
}
@Aspect
@Order(2)
public class LoggingAspect {
// 日志记录逻辑
}
五、底层原理深度解析
5.1 代理机制对比
代理类型 | JDK动态代理 | CGLIB代理 |
---|---|---|
实现方式 | 接口代理 | 子类继承 |
性能 | 创建快,执行慢 | 创建慢,执行快 |
配置触发 | proxyTargetClass=false | proxyTargetClass=true |
方法限制 | 只能代理接口方法 | 可代理非final方法 |
5.2 字节码增强原理
// 伪代码展示CGLIB增强过程
public class UserService$$EnhancerByCGLIB extends UserService {
private MethodInterceptor interceptor;
public void saveUser(User user) {
MethodProxy proxy = MethodProxy.create(...);
interceptor.intercept(this,
UserService.class.getMethod("saveUser"),
new Object[]{user},
proxy);
}
}
六、性能优化实践
6.1 切面执行耗时分析
@Around("serviceLayer()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try {
return pjp.proceed();
} finally {
long nanos = System.nanoTime() - start;
Metrics.record(pjp.getSignature().getName(), nanos);
}
}
6.2 切点表达式优化
// 优化前(性能差)
@Pointcut("execution(* com.example..*.*(..))")
// 优化后(精确匹配)
@Pointcut("execution(public * com.example.service.*Service.*(..))")
七、企业级应用案例
7.1 分布式事务管理
@Aspect
@Component
public class DistributedTransactionAspect {
@Around("@annotation(distributedTx)")
public Object manageTransaction(ProceedingJoinPoint pjp,
DistributedTx distributedTx) throws Throwable {
Transaction tx = TransactionManager.begin();
try {
Object result = pjp.proceed();
tx.commit();
return result;
} catch (Exception ex) {
tx.rollback();
throw ex;
}
}
}
7.2 接口限流控制
@Aspect
@Component
public class RateLimitAspect {
private final RateLimiter limiter = RateLimiter.create(100); // 100 QPS
@Around("execution(* com.example.api.*Controller.*(..))")
public Object limitRate(ProceedingJoinPoint pjp) throws Throwable {
if (limiter.tryAcquire()) {
return pjp.proceed();
} else {
throw new RateLimitExceededException();
}
}
}
八、常见问题解决方案
8.1 切面失效场景
// 错误示例:内部方法调用不会触发AOP
public class UserService {
public void outer() {
this.inner(); // 不会触发切面
}
@Auditable
public void inner() {
// 业务逻辑
}
}
// 正确方案:通过AopContext获取代理对象
public void outer() {
((UserService) AopContext.currentProxy()).inner();
}
8.2 循环依赖处理
// 配置类添加解决循环依赖支持
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {
// ...
}
九、调试与监控方案
9.1 切面调试技巧
// 查看代理类信息
System.out.println(userService.getClass().getName());
// 输出:com.example.UserService$$EnhancerBySpringCGLIB$$...
// 强制使用JDK代理
@EnableAspectJAutoProxy(proxyTargetClass = false)
9.2 监控切面执行
@Aspect
@Component
public class AspectMetrics {
private final MeterRegistry registry;
@Around("@within(org.springframework.stereotype.Service)")
public Object monitorService(ProceedingJoinPoint pjp) throws Throwable {
Timer.Sample sample = Timer.start(registry);
try {
return pjp.proceed();
} finally {
sample.stop(registry.timer("aop.service.methods"));
}
}
}
完整代码示例已托管至Gitee:https://gitee.com/spring-aop-demo
配套工具包包含:
- AOP调试诊断工具
- 切面性能分析脚本
- 企业级切面模板
欢迎在评论区提交您遇到的AOP难题,我们将挑选典型问题进行深度解析!