阅读完需:约 4 分钟
简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;
依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
public class Target {
public void a() {
System.out.println("a 方法");
}
public void b() {
System.out.println("b 方法");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//obj是代理后的子类 ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象
System.out.println("myMethodInterceptor go ");
Object res = proxy.invokeSuper(obj, args);
return res;
}
}
测试
public class TestApp {
public static void main(String[] args) {
Enhancer e = new Enhancer();
e.setSuperclass(Target.class);
e.setCallback(new MyMethodInterceptor());
Target t=(Target) e.create();
t.a();
}
}
myMethodInterceptor go
a 方法
探讨一个问题:
Target这个类里面方法写 this 就是 指的生成的Cglib子类?

在a方法中添加一句输出this
结论:Cglib代理的时候target对象中的this就是Cglib子类 (你可能觉得我说的是废话,子类对象在父类的this指的不是自身吗? 但是Spring Aop里this方法无法增强自身调用)
既然知道了this对象就是指代的自身,那我比如 this.b() 或者 b() 应该也被回调一次了 。
public class Target {
public void a() {
System.out.println(" a 方法");
b();
}
public void b() {
System.out.println(" b 方法");
}
}
其他类不改动代码,测试结果如下: 果然 this.b()方法也被增强了;
myMethodInterceptor go
a 方法
myMethodInterceptor go
b 方法
在 b() 打个断点,下一步就跳进入 MyMethodInterceptor 的 intercept 方法里了 ;这个似乎也没有毛病,其实原因就是 invokeSuper;invokeSuper传入的参数是Cglib代理的子类 ,就相当于 调用 Target$$EnhanceredByCGLIB这个子类的b()方法,肯定会再次进入回调;
如何实现像AOP一样 调用自身无法增强呢?
public class Target {
public void a() {
System.out.println(" a 方法");
b();
}
public void b() {
System.out.println(" b 方法");
}
}
public class MyMethodInterceptor implements MethodInterceptor{
// 关键点 start
private Object target;
public MyMethodInterceptor(Object target) {
super();
this.target = target;
}
// 关键点 end
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("myMethodInterceptor go ");
// Object res = proxy.invokeSuper(obj, args);
// 关键点
Object res = proxy.invoke(target, args);
return res;
}
}
public class TestApp {
public static void main(String[] args) {
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\api");
// 关键点
Target target = new Target();
Enhancer e = new Enhancer();
e.setSuperclass(Target.class);
// 关键点
e.setCallback(new MyMethodInterceptor(target));
Target t=(Target) e.create();
t.a();
}
}
测试结果如下:
myMethodInterceptor go
a 方法
b 方法
这就和AOP的功能一毛一样了吧 ; 区别就在于 invoke 和 invokeSuper : 在我理解看来,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;
查看下Spring CGLIB的Aop , 这个就是执行完 环绕通知 、 前置通知 之后执行业务方法的地方 ,target对象存的是原生的bean,没有被CGLIB代理的对象,所以就无法实现自身调用增强;
该方法是 AopUtils的invokeJoinpointUsingReflection

而与之相反的则是,@Configuration注解下类中 @Bean注解标注方法里的 方法调用,得到的是同一个@Bean对象;
因为 BeanMethodInterceptor 的 interceptor方法 调用的invokeSuper方法 ,比如 getMan2方法调用getMan方法,那个getMan方法调用的是 CGLIB子类的getMan方法 ,此时getMan是增强后的getMan方法,这时候就会检测ThreadLocal当前线程和当前方法是否一致了,不一致尝试从容器中获取该bean对象
