@@ -1145,4 +1145,60 @@ public boolean isAspect(Class<?> clazz) {
11451145
11461146## 总结
11471147
1148- Spring对于AspectJ风格AOP的支持停留在外表(注解)上面,内部的实现仍然是自己的东西。
1148+ Spring对于AspectJ风格AOP的支持停留在外表(注解)上面,内部的实现仍然是自己的东西。
1149+
1150+ # 拾遗
1151+
1152+ ## AOP切面的坑
1153+
1154+ 1 . 定义在private方法上的切面不会被执行,这个很容易理解,毕竟子类不能覆盖父类的私有方法。
1155+ 2 . 同一个代理子类内部的方法相互调用不会再次执行切面。
1156+
1157+ 这里以Cglib为例对第二点进行说明,cglib的相关核心组件可以参考前面CallbackFilter & Callback部分。对于配置了一个切面的典型场景,Spring内部的执行流程可总结如下图:
1158+
1159+ ![ Cglib调用流程] ( images/cglib_invocation.png )
1160+
1161+ 核心便是对目标方法的调用上,这里由CglibMethodInvocation的invokeJoinpoint实现:
1162+
1163+ ``` java
1164+ @Override
1165+ protected Object invokeJoinpoint() throws Throwable {
1166+ if (this . publicMethod) {
1167+ return this . methodProxy. invoke(this . target, this . arguments);
1168+ } else {
1169+ return super . invokeJoinpoint();
1170+ }
1171+ }
1172+ ```
1173+
1174+ 如果是非public方法,那么Spring将使用反射的方法对其进行调用,因为反射将其可访问性设为true。MethodProxy是Cglib对方法代理的抽象,这里的关键是** 方法调用的对象(目标)是我们的原生类对象,而不是Cglib代理子类的对象,这就从根本上决定了对同类方法的调用不会再次经过切面** 。
1175+
1176+ ### 总结
1177+
1178+ 前面aop: aspectj-autoproxy- 属性-expose-proxy一节提到了,Spring允许我们将代理子类暴露出来,可以进行如下配置:
1179+
1180+ ``` xml
1181+ <aop : config expose-proxy =" true" >
1182+ <aop : advisor advice-ref =" simpleMethodInterceptor" pointcut =" execution(* aop.SimpleAopBean.*(..))" />
1183+ </aop : config >
1184+ ```
1185+
1186+ 当我们需要在一个被代理方法中调用同类的方法时(此方法也需要经过切面),可以这样调用:
1187+
1188+ ``` java
1189+ public void testB() {
1190+ System . out. println(" testB执行" );
1191+ ((SimpleAopBean ) AopContext . currentProxy()). testC();
1192+ }
1193+ ```
1194+
1195+ 这里其实是一个ThreadLocal,当Cglib代理子类创建调用链之间便会将代理类设置到其中,DynamicAdvisedInterceptor.intercept相关源码:
1196+
1197+ ``` java
1198+ if (this . advised. exposeProxy) {
1199+ // Make invocation available if necessary.
1200+ oldProxy = AopContext . setCurrentProxy(proxy);
1201+ setProxyContext = true ;
1202+ }
1203+ ```
1204+
0 commit comments