Aop基础
ps:欢迎指正错误,涉及了一点点Spring后置处理器的扫描的内容
@AspectstaticclassAspect1{@org.aspectj.lang.annotation.Before("execution(* foo())")publicvoidbefore1(){System.out.println("before1");}}一个简单的aop类-spring advisor使用
| 元素 | 说明 |
|---|---|
@Aspect | 声明这是一个切面类 |
@Before("execution(* foo())") | 定义增强逻辑在foo()方法执行之前触发 |
foo()方法执行 | 这里就是连接点,也就是增强的“切入位置” |
before1()方法 | 这是通知(Advice),在连接点执行前执行 |
连接点实现
Pointcut是用来描述“哪些类的哪些方法需要被代理增强”的规则。
public interface Pointcut { Pointcut TRUE = TruePointcut.INSTANCE; ClassFilter getClassFilter(); // 过滤类 MethodMatcher getMethodMatcher();// 过滤方法 } ClassFilter:决定哪些类匹配 MethodMatcher:决定哪些方法匹配 两者共同决定拦截范围。切点表达式
切点表达式是在描述匹配规则
execution(*com.xxx.service.*.*(..))哪些方法需要被织入 advice(通知)
把 method/class 匹配规则用代码封装成 Pointcut 对象而已。
这是 AOP 执行链的核心:
每次方法被代理后,都会被包装成一次invoke()调用。
Advisor:Pointcut + MethodInterceptor
MethodInterceptor:增强逻辑(通知)
Proxy:基于 Advisor 判断是否拦截并执行 interceptor.invoke()
代理对象拦截方法 构造一个MethodInvocation调用 interceptor.invoke(invocation)在这个方法里面你可以写增强逻辑 真正执行目标方法是 invocation.proceed()///通知@FunctionalInterfacepublicinterfaceMethodInterceptorextendsInterceptor{@NullableObjectinvoke(@NonnullMethodInvocationinvocation)throwsThrowable;}publicclassLoggingInterceptorimplementsMethodInterceptor{//类似与逻辑点 增强处@OverridepublicObjectinvoke(MethodInvocationinvocation)throwsThrowable{System.out.println("方法执行前日志");// 前置增强Objectresult=invocation.proceed();// 调用目标方法System.out.println("方法执行后日志");returnresult;}}调用方法 AOP 判断:此方法是否匹配Pointcut匹配 → 调用MethodInterceptor.invoke()invoke()内部调用proceed()执行目标方法proceed()执行完后再执行后置增强//简单切面
1.流程1
方法调用流程
2.流传2
代理类组织阶段
3 流程3
切面组织流程
publicstaticvoidmain(String[]args){// 1. 备好切点AspectJExpressionPointcutpointcut=newAspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");///表达式转为pointcut对象// 2. 备好通知MethodInterceptoradvice=invocation->{System.out.println("before...");Objectresult=invocation.proceed();// 调用目标System.out.println("after...");returnresult;};///通知也做到了 连接点(JoinPoint):被增强的方法执行点// 3. 备好切面DefaultPointcutAdvisoradvisor=newDefaultPointcutAdvisor(pointcut,advice);///切面 这是 AOP 的最小工作单元。Target2target=newTarget2();///配置代理工厂ProxyFactoryfactory=newProxyFactory();//设置目标factory.setTarget(target);//设置切面factory.addAdvisor(advisor);Target2proxy=(Target2)factory.getProxy();/* 4. 创建代理 a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现 b. proxyTargetClass = false, 目标没有实现接口, 用 cglib 实现 c. proxyTargetClass = true, 总是使用 cglib 实现 */System.out.println(proxy.getClass());proxy.foo();proxy.bar();}class com.itheima.a15.A15$Target2$$EnhancerBySpringCGLIB$$ea384bdf before... target2 foo after... target2 bar表达式解析 →PointcutMethodInterceptor→ 通知逻辑Pointcut+Advice→Advisor↓ProxyFactory↓ 创建代理对象(JDK/CGLIB) ↓ 调用方法 ↓ 匹配切点? 是 → 调用 advice.invoke()beforeproceed()→ 调用真实方法 after 否 → 直接执行真实方法| 步骤序号 | 原理流程描述 | 关键类/方法 | 逆向推断的实现细节与原理 |
|---|---|---|---|
| 1 | 解析切点表达式 | AspectJExpressionPointcut | 利用 AspectJ 表达式解析器解析"execution(* foo())",生成能匹配方法的规则对象。 |
| 2 | 构建通知实例 | MethodInterceptor(Lambda) | 编写通知逻辑,封装成拦截器,待会代理类方法调用时会执行它。 |
| 3 | 封装切点与通知为 Advisor | DefaultPointcutAdvisor | Advisor 是切点+通知的组合体,方便统一管理和应用。 |
| 4 | 初始化代理工厂 | ProxyFactory | 设置目标对象、Advisor 列表、代理类型(JDK或CGLIB),准备生成代理。 |
| 5 | 选择代理实现方式 | AopProxyFactory+JdkDynamicAopProxy/ObjenesisCglibAopProxy | 根据目标类是否实现接口和配置,决定用 JDK 动态代理或 CGLIB 动态字节码生成代理类。 |
| 6 | 动态生成代理类 | ProxyGenerator(JDK) 或 ASM/Objenesis (CGLIB) | 反编译/逆向:生成的代理类继承/实现目标类/接口,重写匹配方法,织入拦截器调用逻辑。 |
| 7 | 代理类重写匹配方法逻辑 | 代理类的invoke或方法重写 | 调用MethodInterceptor.invoke(),执行通知前置增强,调用目标方法,执行后置增强。 |
| 8 | 未匹配方法直接委托调用目标方法 | 代理类的非匹配方法实现 | 直接调用目标类对应方法,不执行通知增强。 |
| 9 | 方法调用流程 | 代理对象的调用链 | 代理对象.foo() -> MethodInterceptor.invoke() -> invocation.proceed() -> 目标对象.foo() |
| 10 | 异常处理 | UndeclaredThrowableException | 拦截器捕获异常时封装成运行时异常,保证调用链异常统一处理。 |
代理实现选择
/* 4. 创建代理 a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现 b. proxyTargetClass = false, 目标没有实现接口, 用 cglib 实现 c. proxyTargetClass = true, 总是使用 cglib 实现 */jdk代理使用
Target1target=newTarget1();ProxyFactoryfactory=newProxyFactory();factory.setTarget(target);factory.addAdvisor(advisor);factory.setInterfaces(target.getClass().getInterfaces());factory.setProxyTargetClass(false);I1proxy=(I1)factory.getProxy();System.out.println(proxy.getClass());proxy.foo();proxy.bar();class com.itheima.a15.$Proxy2 before... target1 foo after... target1 bara. Spring 的代理选择规则 b. 底层的切点实现 c. 底层的通知实现 d. ProxyFactory 是用来创建代理的核心实现, 用 AopProxyFactory 选择具体代理实现 - JdkDynamicAopProxy - ObjenesisCglibAopProxy准备aop
创建代理-代理原始类,创建切点 通知 放入创建的切面,由代理类来进行匹配,成功就调用切莫的通知内的代码,没有就调用元方法
切点匹配
切点匹配///1.根据方法名字增强AspectJExpressionPointcutpt1=newAspectJExpressionPointcut();pt1.setExpression("execution(* bar())");System.out.println(pt1.matches(T1.class.getMethod("foo"),T1.class));falseSystem.out.println(pt1.matches(T1.class.getMethod("bar"),T1.class));true///根据注解匹配AspectJExpressionPointcutpt2=newAspectJExpressionPointcut();pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");System.out.println(pt2.matches(T1.class.getMethod("foo"),T1.class));System.out.println(pt2.matches(T1.class.getMethod("bar"),T1.class));staticclassT1{@Transactionalpublicvoidfoo(){}publicvoidbar(){}}事务不是这样实现–只能匹配方法-事务有类和接口
事务实现扫描
staticclassT1{@Transactionalpublicvoidfoo(){}publicvoidbar(){}}@TransactionalstaticclassT2{publicvoidfoo(){}}@TransactionalinterfaceI3{voidfoo();}staticclassT3implementsI3{publicvoidfoo(){}}实现注解扫描 重写matches方法
StaticMethodMatcherPointcutpt3=newStaticMethodMatcherPointcut(){@Overridepublicbooleanmatches(Methodmethod,Class<?>targetClass){// 检查方法上是否加了 Transactional 注解MergedAnnotationsannotations=MergedAnnotations.from(method);if(annotations.isPresent(Transactional.class)){returntrue;}// 查看类上是否加了 Transactional 注解annotations=MergedAnnotations.from(targetClass,MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);if(annotations.isPresent(Transactional.class)){returntrue;}returnfalse;}};System.out.println(pt3.matches(T1.class.getMethod("foo"),T1.class));System.out.println(pt3.matches(T1.class.getMethod("bar"),T1.class));System.out.println(pt3.matches(T2.class.getMethod("foo"),T2.class));System.out.println(pt3.matches(T3.class.getMethod("foo"),T3.class));从Aspect到advisor
高级的@aspect介绍
低级的advisor介绍
| 对比项 | 高级切面(@Aspect) | 低级切面(Advisor) | 关系与转换 |
|---|---|---|---|
| 定义位置 | 基于@AspectJ 注解或 XML 声明的“面向切面编程”方式 | Spring AOP 底层的切面实现接口/类(Advisor、PointcutAdvisor) | 高级切面最终会被解析成一个或多个 Advisor 对象 |
| 开发难度 | 简单直观:直接写普通 Java 类,配合@Before/@After/@Around等注解即可 | 繁琐底层:需要手动实现MethodInterceptor、Pointcut、Advisor等接口 | Spring 在启动时会解析 @Aspect 并自动生成对应的 Advisor |
| 切点表达 | 使用@Pointcut+ AspectJ 表达式(execution(...)等) | 使用Pointcut接口或现成类(如AspectJExpressionPointcut) | @Pointcut会被转为AspectJExpressionPointcut实例 |
| 通知定义 | 注解方式直接绑定(@Before、@Around等) | 通过实现 Advice 接口(MethodBeforeAdvice、AfterReturningAdvice、MethodInterceptor) | 每个注解通知会变成一个对应类型的 Advice 实例 |
| 运行机制 | 开发者只看到“声明式”的切面类 | 底层是 Advisor 持有一个 Advice + 一个 Pointcut | Advisor = Pointcut + Advice |
| 适用场景 | 业务代码中快速实现切面逻辑 | 框架开发、AOP 底层扩展,需要精细控制切面行为 | 高级切面其实是低级 API 的语法糖 |
| 本质 | 面向业务的声明式切面 | 面向框架的底层切面 | 高级切面 = 封装 + 自动生成低级切面对象 |
高级切面
本质还是转为低级切面处理
低级切面
1.切入点
// 1. 备好切点AspectJExpressionPointcutpointcut=newAspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");// 2. 备好通知MethodInterceptoradvice=invocation->{System.out.println("before...");Objectresult=invocation.proceed();// 调用目标System.out.println("after...");returnresult;};// 3. 备好切面DefaultPointcutAdvisoradvisor=newDefaultPointcutAdvisor(pointcut,advice);切点-通知-切面切面
通知
test
Target1target=newTarget1();ProxyFactoryfactory=newProxyFactory();factory.setTarget(target);factory.addAdvisor(advisor);factory.setInterfaces(target.getClass().getInterfaces());///如果 Target2 没有实现任何接口 → 会抛异常(JDK 代理没法用)。factory.setProxyTargetClass(false);I1proxy=(I1)factory.getProxy();System.out.println(proxy.getClass());proxy.foo();proxy.bar();测试
// 代理能否重复被代理publicclassA15_1{publicstaticvoidmain(String[]args){GenericApplicationContextcontext=newGenericApplicationContext();context.registerBean("myConfig",MyConfig.class);context.registerBean(ConfigurationClassPostProcessor.class);context.registerBean("aspect1",Aspect1.class);context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);//切面扫描context.refresh();Bean1bean1=context.getBean(Bean1.class);bean1.foo();System.out.println(bean1.getClass());// 此代理是为了解决功能增强问题System.out.println(context.getBean("scopedTarget.bean1").getClass());}staticclassMyConfig{// 此代理是为了解决单例注入多例问题@Bean@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)publicBean1bean1(){returnnewBean1();}}staticclassBean1{publicvoidfoo(){System.out.println("bean1 foo");}}@Aspect//注解扫描staticclassAspect1{@Around("execution(* foo())")publicObjectbefore(ProceedingJoinPointpjp)throwsThrowable{System.out.println("aspect1 around");returnpjp.proceed();}}}AnnotationAwareAspectJAutoProxyCreator 扫描了aop的注解
使用aop的后缀处理器**
Bean测试
GenericApplicationContextcontext=newGenericApplicationContext();context.registerBean("aspect1",Aspect1.class);context.registerBean("config",Config.class);context.registerBean(ConfigurationClassPostProcessor.class);context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);// BeanPostProcessor// 创建 -> (*) 依赖注入 -> 初始化 (*)context.refresh();AnnotationAwareAspectJAutoProxyCreator切面类处理
bean后置处理器 作用-找到切面
高级切面转换低级切面
根据切面创建代理对象
发现处理器阶段
扩展点
创建 -> (*) 依赖注入 -> 初始化 (*)主动调用bean处理器
作用 : 找到有资格的切面类-查找低级切面-高级切面需要转换
自己调用 查看哪些切面内匹配上了
AnnotationAwareAspectJAutoProxyCreatorcreator=context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);List<Advisor>advisors=creator.findEligibleAdvisors(Target2.class,"target2");for(Advisoradvisor:advisors){System.out.println(advisor);}创建代理
有资格的切面创建代理
第二个重要方法 wrapIfNecessary a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理Objecto1=creator.wrapIfNecessary(newTarget1(),"target1","target1");/// 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理System.out.println(o1.getClass());Objecto2=creator.wrapIfNecessary(newTarget2(),"target2","target2");System.out.println(o2.getClass());((Target1)o1).foo();classorg.springframework.aop.framework.autoproxy.A17$Target1$$EnhancerBySpringCGLIB$$5748c5d2//代理classorg.springframework.aop.framework.autoproxy.A17$Target2///原始aspect1 before1...aspect1 before2...advice3 before...target1 foo advice3 after...代理创建调用
是否有必要创建代理
代理创建时间
创建 -> () 依赖注入 -> 初始化 ()
情况1
@Configuration@BeanpublicAdvisoradvisor(MethodInterceptoradvice){AspectJExpressionPointcutpointcut=newAspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");returnnewDefaultPointcutAdvisor(pointcut,advice);}@BeanpublicMethodInterceptoradvice(){return(MethodInvocationinvocation)->{System.out.println("before...");returninvocation.proceed();};}@BeanpublicBean1bean1(){returnnewBean1();}@BeanpublicBean2bean2(){returnnewBean2();}}//代理staticclassBean1{publicvoidfoo(){}publicBean1(){System.out.println("Bean1()");}@PostConstructpublicvoidinit(){//初始化System.out.println("Bean1 init()");}}staticclassBean2{publicBean2(){System.out.println("Bean2()");}@AutowiredpublicvoidsetBean1(Bean1bean1){System.out.println("Bean2 setBean1(bean1) class is: "+bean1.getClass());}@PostConstructpublicvoidinit(){System.out.println("Bean2 init()");}}publicstaticvoidmain(String[]args){GenericApplicationContextcontext=newGenericApplicationContext();context.registerBean(ConfigurationClassPostProcessor.class);context.registerBean(Config.class);//配置类context.refresh();context.close();}Bean1()构造Bean1init()初始化[TRACE]17:15:47.625[main]o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator-Creatingimplicit proxyforbean'bean1'with0common interceptors and2specific interceptors/// 创建了bean1的代理对象,并且放入容器中Bean2()Bean2setBean1(bean1)classis:classorg.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$2fba3bac/// 把bean1的代理对象注入进去Bean2init()初始化情况2
代理创建时机
循环依赖
Bean1()Bean2()[TRACE]17:17:14.751[main]o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator-Creatingimplicit proxyforbean'bean1'with0common interceptors and2specific interceptorsBean2setBean1(bean1)classis:classorg.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$df1706a0//注入代理对象bean1 bean1提前创建,再初始化前Bean2init()///Bean1setBean2(bean2)classis:classorg.springframework.aop.framework.autoproxy.A17_1$Bean2///再次注入bean2Bean1init()使用了延迟加载技术,也就是搭了个壳子,但是内容不完整,.之后大家创建好了,再补回去
order注解
@Aspect// 高级切面类@Order(1)staticclassAspect1{@Before("execution(* foo())")publicvoidbefore1(){System.out.println("aspect1 before1...");}@Before("execution(* foo())")publicvoidbefore2(){System.out.println("aspect1 before2...");}}@Bean// 低级切面publicAdvisoradvisor3(MethodInterceptoradvice3){AspectJExpressionPointcutpointcut=newAspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");DefaultPointcutAdvisoradvisor=newDefaultPointcutAdvisor(pointcut,advice3);advisor.setOrder(0);returnadvisor;}控制切面顺序 @Order(1) advisor.setOrder(0);
默认低级优先级高
高级切面转换低级切面
定义通知和切面连接点
staticclassAspect{@Before("execution(* foo())")publicvoidbefore1(){System.out.println("before1");}@Before("execution(* foo())")publicvoidbefore2(){System.out.println("before2");}}test测试
找到类-解析切点,创建切点表达式, 创建通知 创建切面类
publicstaticvoidmain(String[]args)throwsThrowable{//切面实例工厂AspectInstanceFactoryfactory=newSingletonAspectInstanceFactory(newAspect());// 高级切面转低级切面类List<Advisor>list=newArrayList<>();for(Methodmethod:Aspect.class.getDeclaredMethods()){//方法解析if(method.isAnnotationPresent(Before.class)){// 解析切点Stringexpression=method.getAnnotation(Before.class).value();AspectJExpressionPointcutpointcut=newAspectJExpressionPointcut();pointcut.setExpression(expression);//设计切点// 通知类的创建--前置通知AspectJMethodBeforeAdviceadvice=newAspectJMethodBeforeAdvice(method,pointcut,factory);// 切面Advisoradvisor=newDefaultPointcutAdvisor(pointcut,advice);list.add(advisor);}}for(Advisoradvisor:list){System.out.println(advisor);}}org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.autoproxy.A17_2$Aspect.before1()]; aspect name ''] ------------------------------------------ org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.autoproxy.A17_2$Aspect.before2()]; aspect name ''] ------------------------------------------都从高级切面转换成了低级切面
静态通知调用
A18代码
| 知识点 | 说明 | 关键类 / 接口 | 作用与意义 |
|---|---|---|---|
| 高级切面 → 低级切面 | @Before、@AfterReturning、@Around 等注解切面,运行时会被解析为Advisor(包含切点 Pointcut 和通知 Advice) | Advisor、Pointcut、Advice、AspectInstanceFactory | 高级注解只是语法糖,底层统一转换成低级切面对象,方便后续代理机制处理 |
| 通知类型与实现类 | 不同注解对应不同 Advice 实现类 | AspectJMethodBeforeAdvice(前置)、AspectJAfterReturningAdvice(返回后)、AspectJAroundAdvice(环绕) | 用具体类封装通知逻辑和切点表达式 |
| 统一适配为环绕通知 | Spring 内部会把所有通知转成MethodInterceptor(环绕调用形式) | MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter | 适配器模式:对外保留多种注解,对内统一为 MethodInterceptor,方便调用链执行 |
| 调用链机制 | 多个 Advice 嵌套调用目标方法,形成责任链 | MethodInvocation、ReflectiveMethodInvocation | 每个环绕通知调用proceed()进入下一个通知,直到目标方法执行 |
| ExposeInvocationInterceptor | 在当前线程暴露 MethodInvocation 对象 | ExposeInvocationInterceptor.INSTANCE | 让 Before、After 类型的 Advice 可以获取当前调用上下文 |
| 动态拦截器获取 | 代理工厂根据方法和类获取执行时的拦截器列表 | proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(...) | 在方法调用前,组装出一条包含所有环绕通知的执行链 |
| 设计模式应用 | 使用适配器模式和责任链模式 | Adapter Pattern、Chain of Responsibility | 适配器用于统一不同通知类型,责任链用于按顺序执行多个通知 |
其实无论ProxyFactory基于哪种方式创建代理,最后干活(调用 advice)的是一个MethodInvocation对象 a.因为 advisor 有多个,且一个套一个调用,因此需要一个调用链对象,即MethodInvocationb.MethodInvocation要知道 advice 有哪些,还要知道目标,调用次序如下 将MethodInvocation放入当前线程|->before1-----------------------------------从当前线程获取MethodInvocation||||->before2--------------------|从当前线程获取MethodInvocation|||||||->target------目标 advice2 advice1||||||->after2---------------------||||->after1------------------------------------c.从上图看出,环绕通知才适合作为 advice,因此其他 before、afterReturning 都会被转换成环绕通知 d.统一转换为环绕通知,体现的是设计模式中的适配器模式-对外是为了方便使用要区分 before、afterReturning-对内统一都是环绕通知,统一用MethodInterceptor表示18_1
| 知识点 | 说明 | 关键类 / 方法 | 作用与意义 |
|---|---|---|---|
| MethodInvocation 接口 | 统一抽象方法调用过程,包含目标方法、参数、调用链控制等 | proceed()、getMethod()、getArguments() | 封装一次“方法调用”的上下文,支持多层拦截器嵌套 |
| MethodInterceptor 接口 | 环绕通知的统一接口,负责在调用前后织入逻辑 | invoke(MethodInvocation) | 用于在目标方法执行前后加入增强逻辑(before/after) |
| 递归调用链 | proceed()依次调用下一个拦截器;拦截器内部再次调用proceed() | MyInvocation.proceed() | 使用递归(或迭代)模型处理多层嵌套,最终调用目标方法 |
| 终止条件 | 调用计数大于拦截器数量时执行目标方法 | if (count > methodInterceptorList.size()) | 防止无限递归,保证链条最后能到目标方法 |
| 顺序控制 | count++保证按添加顺序调用每个拦截器 | 计数器变量count | 确保责任链从第一个到最后一个依次执行 |
a19
| 分类 | 特点 | 运行时表现 | 核心类 / 接口 | 性能影响 | 适用场景 |
|---|---|---|---|---|---|
| 静态通知调用 | 切点表达式不带参数绑定(例:execution(* foo(..))) | 执行时直接调用拦截器,不需要动态匹配 | MethodInterceptor | 高(无额外匹配开销) | 方法签名固定,不需要访问实参 |
| 动态通知调用 | 切点表达式带参数绑定(例:execution(* foo(..)) && args(x)) | 执行时需先执行切点匹配(MethodMatcher.matches())并绑定参数,再调用拦截器 | InterceptorAndDynamicMethodMatcher、MethodMatcher、MethodInterceptor | 低(多一次匹配与绑定步骤) | 需要访问方法实参或按参数条件增强的方法 |
| 切面解析器 | 解析@Aspect并生成 Advisor | 自动扫描切面类,创建切点和通知 | AnnotationAwareAspectJAutoProxyCreator | - | Spring 自动代理机制核心 |
| 运行时动态封装 | 对动态通知,Spring 会将切点对象与拦截器封装在一起 | 执行时先匹配后调用 | InterceptorAndDynamicMethodMatcher | 略低 | 动态通知必需 |
| 调试工具方法 | 反射查看InterceptorAndDynamicMethodMatcher内部结构 | 可看到methodMatcher与methodInterceptor | 反射 API | - | 分析 Spring AOP 内部执行机制 |
| 性能建议 | 高频方法使用静态通知,减少运行时匹配开销 | - | - | 性能敏感场景中减少动态通知 | 高频调用、性能敏感的业务逻辑 |