Spring AOP深度解析引言面向切面编程Aspect-Oriented ProgrammingAOP是Spring框架的核心功能之一它允许开发者将横切关注点如日志、事务、安全与业务逻辑分离提高代码的模块化程度。本文将深入剖析Spring AOP的底层实现、核心概念、通知类型、切点表达式以及在Spring Boot中的最佳实践。一、AOP核心概念1.1 基本术语Join Point连接点程序执行的某个位置Spring AOP中只有方法调用连接点Pointcut切点用于匹配连接点的表达式决定哪些连接点被拦截Advice通知切面在连接点执行的代码包括前置通知、后置通知等Aspect切面通知和切点的组合Weaving织入将切面应用到目标对象的过程。1.2 Spring AOP vs AspectJSpring AOP只支持方法级别的拦截采用代理模式实现AspectJ支持字段、构造函数等更细粒度的拦截采用编译时或加载时织入。二、通知类型2.1 前置通知Aspect Component public class LoggingAspect { Before(execution(* com.example.service.*.*(..))) public void before(JoinPoint joinPoint) { String methodName joinPoint.getSignature().getName(); Object[] args joinPoint.getArgs(); System.out.println(Before: methodName with args: Arrays.toString(args)); } }2.2 后置通知Aspect Component public class PerformanceAspect { AfterReturning( pointcut execution(* com.example.service.*.*(..)), returning result ) public void afterReturning(JoinPoint joinPoint, Object result) { String methodName joinPoint.getSignature().getName(); System.out.println(After returning: methodName result: result); } AfterThrowing( pointcut execution(* com.example.service.*.*(..)), throwing exception ) public void afterThrowing(JoinPoint joinPoint, Exception exception) { String methodName joinPoint.getSignature().getName(); System.err.println(Exception in: methodName message: exception.getMessage()); } }2.3 环绕通知Aspect Component public class TransactionAspect { Autowired private PlatformTransactionManager transactionManager; Around(execution(* com.example.service.*.*(..))) public Object around(ProceedingJoinPoint joinPoint) throws Throwable { String methodName joinPoint.getSignature().getName(); TransactionStatus status transactionManager .getTransaction(new DefaultTransactionDefinition()); try { Object result joinPoint.proceed(); transactionManager.commit(status); return result; } catch (Exception e) { transactionManager.rollback(status); throw e; } } }三、切点表达式3.1 常用表达式// 方法签名匹配 execution(public * com.example.service.UserService.get*(..)) // 公共方法 execution(* com.example.service.*.*(..)) // service包下所有方法 execution(* com.example.service..*(..)) // service及其子包 // 参数匹配 execution(* *(String, Integer)) // 两个参数 execution(* *(String, ..)) // 第一个参数String execution(* com.example.service.UserService.*(..)) // 包括子类 // 注解匹配 annotation(org.springframework.stereotype.Service) // 带Service注解 args(com.example.annotation.Transactional) // 带Transactional参数3.2 自定义切点Aspect Component public class CustomPointcuts { Pointcut(execution(* com.example.service.*.*(..))) public void serviceLayer() {} Pointcut(execution(* com.example.repository.*.*(..))) public void repositoryLayer() {} Pointcut(serviceLayer() || repositoryLayer()) public void applicationLayer() {} Pointcut(within(com.example.service.*)) public void inServicePackage() {} }四、切面优先级4.1 Order注解Aspect Order(1) Component public class SecurityAspect { // 最高优先级 } Aspect Order(2) Component public class LoggingAspect { // 次高优先级 } Aspect Order(Ordered.LOWEST_PRECEDENCE) Component public class PerformanceAspect { // 最低优先级 }五、Spring Boot集成5.1 启用AOPdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-aop/artifactId /dependencyspring: aop: auto: true proxy-target-class: true expose-proxy: true5.2 自定义注解切面Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Retryable { int maxAttempts() default 3; long delay() default 1000; Class? extends Throwable[] value() default {}; } Aspect Component public class RetryAspect { Around(annotation(retryable)) public Object around(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable { int attempts retryable.maxAttempts(); long delay retryable.delay(); Class? extends Throwable[] exceptions retryable.value(); for (int i 0; i attempts; i) { try { return joinPoint.proceed(); } catch (Throwable e) { if (i attempts - 1 || !isRetryable(e, exceptions)) { throw e; } Thread.sleep(delay); } } throw new RuntimeException(Should not reach here); } private boolean isRetryable(Throwable e, Class? extends Throwable[] exceptions) { for (Class? extends Throwable ex : exceptions) { if (ex.isInstance(e)) { return true; } } return false; } }六、JoinPoint详解6.1 获取信息Aspect Component public class JoinPointAspect { Before(execution(* com.example.service.*.*(..))) public void before(JoinPoint joinPoint) { // 获取方法签名 Signature signature joinPoint.getSignature(); String className signature.getDeclaringTypeName(); String methodName signature.getName(); // 获取参数 Object[] args joinPoint.getArgs(); // 获取目标对象 Object target joinPoint.getTarget(); // 获取代理对象 Object proxy joinPoint.getThis(); // 获取方法参数名 MethodSignature ms (MethodSignature) signature; String[] paramNames ms.getParameterNames(); System.out.println(className . methodName); } }6.2 MethodSignatureAspect Component public class MethodSignatureAspect { Before(execution(* com.example.service.*.*(..))) public void signatureInfo(JoinPoint joinPoint) { MethodSignature signature (MethodSignature) joinPoint .getSignature(); // 返回类型 Class? returnType signature.getReturnType(); // 参数类型 Type[] parameterTypes signature.getParameterTypes(); // 参数名 String[] parameterNames signature.getParameterNames(); // 异常类型 Class?[] exceptionTypes signature.getExceptionTypes(); } }七、织入方式7.1 JDK动态代理// 基于接口的代理 public class JdkProxyExample { public static T T createProxy(T target, ClassT interfaceClass) { return (T) Proxy.newProxyInstance( interfaceClass.getClassLoader(), new Class[]{interfaceClass}, (proxy, method, args) - { System.out.println(Before: method.getName()); Object result method.invoke(target, args); System.out.println(After: method.getName()); return result; } ); } }7.2 CGLIB代理// 基于类的代理 public class CglibProxyExample { public static T T createProxy(T target) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) - { System.out.println(Before: method.getName()); Object result proxy.invokeSuper(obj, args); System.out.println(After: method.getName()); return result; }); return (T) enhancer.create(); } }八、最佳实践8.1 避免切面循环依赖// 错误切面依赖注入自身 Aspect Component public class BadAspect { Autowired private BadAspect self; // 错误 Around(execution(* *.method(..))) public Object around(ProceedingJoinPoint pjp) { return self.proceed(pjp); } }8.2 切面中的事务Aspect Component Order(1) // 在事务切面之前执行 public class LoggingAspect { Autowired private AuditService auditService; Around(execution(* com.example.service.*.*(..))) public Object log(ProceedingJoinPoint pjp) throws Throwable { String action pjp.getSignature().getName(); Object[] args pjp.getArgs(); try { Object result pjp.proceed(); auditService.logSuccess(action, args); return result; } catch (Exception e) { auditService.logFailure(action, args, e); throw e; } } }总结Spring AOP是处理横切关注点的强大工具通过切面可以将日志、事务、安全等功能与业务逻辑解耦。理解AOP的核心概念、切点表达式和各种通知类型是正确使用AOP的基础。在实际应用中应该合理设计切面避免过度使用导致性能问题和代码复杂度增加。
Spring AOP深度解析
发布时间:2026/5/19 1:37:13
Spring AOP深度解析引言面向切面编程Aspect-Oriented ProgrammingAOP是Spring框架的核心功能之一它允许开发者将横切关注点如日志、事务、安全与业务逻辑分离提高代码的模块化程度。本文将深入剖析Spring AOP的底层实现、核心概念、通知类型、切点表达式以及在Spring Boot中的最佳实践。一、AOP核心概念1.1 基本术语Join Point连接点程序执行的某个位置Spring AOP中只有方法调用连接点Pointcut切点用于匹配连接点的表达式决定哪些连接点被拦截Advice通知切面在连接点执行的代码包括前置通知、后置通知等Aspect切面通知和切点的组合Weaving织入将切面应用到目标对象的过程。1.2 Spring AOP vs AspectJSpring AOP只支持方法级别的拦截采用代理模式实现AspectJ支持字段、构造函数等更细粒度的拦截采用编译时或加载时织入。二、通知类型2.1 前置通知Aspect Component public class LoggingAspect { Before(execution(* com.example.service.*.*(..))) public void before(JoinPoint joinPoint) { String methodName joinPoint.getSignature().getName(); Object[] args joinPoint.getArgs(); System.out.println(Before: methodName with args: Arrays.toString(args)); } }2.2 后置通知Aspect Component public class PerformanceAspect { AfterReturning( pointcut execution(* com.example.service.*.*(..)), returning result ) public void afterReturning(JoinPoint joinPoint, Object result) { String methodName joinPoint.getSignature().getName(); System.out.println(After returning: methodName result: result); } AfterThrowing( pointcut execution(* com.example.service.*.*(..)), throwing exception ) public void afterThrowing(JoinPoint joinPoint, Exception exception) { String methodName joinPoint.getSignature().getName(); System.err.println(Exception in: methodName message: exception.getMessage()); } }2.3 环绕通知Aspect Component public class TransactionAspect { Autowired private PlatformTransactionManager transactionManager; Around(execution(* com.example.service.*.*(..))) public Object around(ProceedingJoinPoint joinPoint) throws Throwable { String methodName joinPoint.getSignature().getName(); TransactionStatus status transactionManager .getTransaction(new DefaultTransactionDefinition()); try { Object result joinPoint.proceed(); transactionManager.commit(status); return result; } catch (Exception e) { transactionManager.rollback(status); throw e; } } }三、切点表达式3.1 常用表达式// 方法签名匹配 execution(public * com.example.service.UserService.get*(..)) // 公共方法 execution(* com.example.service.*.*(..)) // service包下所有方法 execution(* com.example.service..*(..)) // service及其子包 // 参数匹配 execution(* *(String, Integer)) // 两个参数 execution(* *(String, ..)) // 第一个参数String execution(* com.example.service.UserService.*(..)) // 包括子类 // 注解匹配 annotation(org.springframework.stereotype.Service) // 带Service注解 args(com.example.annotation.Transactional) // 带Transactional参数3.2 自定义切点Aspect Component public class CustomPointcuts { Pointcut(execution(* com.example.service.*.*(..))) public void serviceLayer() {} Pointcut(execution(* com.example.repository.*.*(..))) public void repositoryLayer() {} Pointcut(serviceLayer() || repositoryLayer()) public void applicationLayer() {} Pointcut(within(com.example.service.*)) public void inServicePackage() {} }四、切面优先级4.1 Order注解Aspect Order(1) Component public class SecurityAspect { // 最高优先级 } Aspect Order(2) Component public class LoggingAspect { // 次高优先级 } Aspect Order(Ordered.LOWEST_PRECEDENCE) Component public class PerformanceAspect { // 最低优先级 }五、Spring Boot集成5.1 启用AOPdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-aop/artifactId /dependencyspring: aop: auto: true proxy-target-class: true expose-proxy: true5.2 自定义注解切面Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Retryable { int maxAttempts() default 3; long delay() default 1000; Class? extends Throwable[] value() default {}; } Aspect Component public class RetryAspect { Around(annotation(retryable)) public Object around(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable { int attempts retryable.maxAttempts(); long delay retryable.delay(); Class? extends Throwable[] exceptions retryable.value(); for (int i 0; i attempts; i) { try { return joinPoint.proceed(); } catch (Throwable e) { if (i attempts - 1 || !isRetryable(e, exceptions)) { throw e; } Thread.sleep(delay); } } throw new RuntimeException(Should not reach here); } private boolean isRetryable(Throwable e, Class? extends Throwable[] exceptions) { for (Class? extends Throwable ex : exceptions) { if (ex.isInstance(e)) { return true; } } return false; } }六、JoinPoint详解6.1 获取信息Aspect Component public class JoinPointAspect { Before(execution(* com.example.service.*.*(..))) public void before(JoinPoint joinPoint) { // 获取方法签名 Signature signature joinPoint.getSignature(); String className signature.getDeclaringTypeName(); String methodName signature.getName(); // 获取参数 Object[] args joinPoint.getArgs(); // 获取目标对象 Object target joinPoint.getTarget(); // 获取代理对象 Object proxy joinPoint.getThis(); // 获取方法参数名 MethodSignature ms (MethodSignature) signature; String[] paramNames ms.getParameterNames(); System.out.println(className . methodName); } }6.2 MethodSignatureAspect Component public class MethodSignatureAspect { Before(execution(* com.example.service.*.*(..))) public void signatureInfo(JoinPoint joinPoint) { MethodSignature signature (MethodSignature) joinPoint .getSignature(); // 返回类型 Class? returnType signature.getReturnType(); // 参数类型 Type[] parameterTypes signature.getParameterTypes(); // 参数名 String[] parameterNames signature.getParameterNames(); // 异常类型 Class?[] exceptionTypes signature.getExceptionTypes(); } }七、织入方式7.1 JDK动态代理// 基于接口的代理 public class JdkProxyExample { public static T T createProxy(T target, ClassT interfaceClass) { return (T) Proxy.newProxyInstance( interfaceClass.getClassLoader(), new Class[]{interfaceClass}, (proxy, method, args) - { System.out.println(Before: method.getName()); Object result method.invoke(target, args); System.out.println(After: method.getName()); return result; } ); } }7.2 CGLIB代理// 基于类的代理 public class CglibProxyExample { public static T T createProxy(T target) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) - { System.out.println(Before: method.getName()); Object result proxy.invokeSuper(obj, args); System.out.println(After: method.getName()); return result; }); return (T) enhancer.create(); } }八、最佳实践8.1 避免切面循环依赖// 错误切面依赖注入自身 Aspect Component public class BadAspect { Autowired private BadAspect self; // 错误 Around(execution(* *.method(..))) public Object around(ProceedingJoinPoint pjp) { return self.proceed(pjp); } }8.2 切面中的事务Aspect Component Order(1) // 在事务切面之前执行 public class LoggingAspect { Autowired private AuditService auditService; Around(execution(* com.example.service.*.*(..))) public Object log(ProceedingJoinPoint pjp) throws Throwable { String action pjp.getSignature().getName(); Object[] args pjp.getArgs(); try { Object result pjp.proceed(); auditService.logSuccess(action, args); return result; } catch (Exception e) { auditService.logFailure(action, args, e); throw e; } } }总结Spring AOP是处理横切关注点的强大工具通过切面可以将日志、事务、安全等功能与业务逻辑解耦。理解AOP的核心概念、切点表达式和各种通知类型是正确使用AOP的基础。在实际应用中应该合理设计切面避免过度使用导致性能问题和代码复杂度增加。