package test.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Test {
public static String test(){
return "Test.class test.Method";
}
public static String toString(String str){
return "Test.class toString.Method";
}
public String print(){
return this.getClass().toString();
}
static class TestC {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Test.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
Test test = (Test)enhancer.create();
System.out.println(test.test());
System.out.println(test.toString("aaa"));
System.out.println(test.print());
/*
System.out.println(test.getClass());
System.out.println(test.hashCode());*/
}
}
}
class TestB extends Test{
}
异常:
Test.class test.Method
Test.class toString.Method
Exception in thread "main" java.lang.StackOverflowError
at java.lang.Exception.<init>(Exception.java:102)
at java.lang.ReflectiveOperationException.<init>(ReflectiveOperationException.java:89)
at java.lang.reflect.InvocationTargetException.<init>(InvocationTargetException.java:72)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
at test.cglib.TestB$$EnhancerByCGLIB$$268c99b1.print(<generated>)
at test.cglib.Test$$FastClassByCGLIB$$85a72dbb.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at test.cglib.Test$TestC$1.intercept(Test.java:35)
解决办法: 将 proxy.invoke(obj, args); 方法改为 proxy.invokeSuper(obj, args);方法
问题出现的原因:
在cglib代理之前,加入如下的代码: System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\\\classes");cglib 就会将代理过程中创建的类(class文件)保存到指定的路径中,方便我们反编译查看.
在看看,invoke 方法和superInvoke 方法源码的区别
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
发现区别就在return这一行, 首先他们都会执行一下init方法,然后 得到FastClassInfo对象,实现包括f2,f1两个对象,invoke 是调用f1对象的invoke方法,而invokeSuper 方法则是调用f2的invoke方法, 程序运行结束可以在指定目录的test目录下,发现三个class文件,
如图中所示,第一个是f2对象,第二个是创建的代理对象,第三个是f1对象,经过反编译发现,发现被代理类中的每个方法,在代理类中,都会有对应的两个方法,一个是同名方法(例如:print),一个代理的CGLIB$print$0方法, 在反编译两个FastClass 类,对比他们的invoke方法, 发现 f2 对象是直接调用代理的方法,里面直接super.原方法就执行,所有invokeSuper方法会执行成功,而f1对象是还会判断,在去调用实先MethodInterceptor 的intercept 方法
具体原因,及 invoke 方法 和 invokeSuper() 方法 的区别,请看这篇博客:https://blog.csdn.net/makecontral/article/details/79593732