cglib 通过MethodInterceptor 回调,调用方法,出现堆栈异常

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

猜你喜欢

转载自blog.csdn.net/kzcming/article/details/81873950
今日推荐