JDK动态代理的学习与理解之:invoke方法为什么不能method.invoke(proxy,args[])

在学习动态代理时,始终让我迷茫的一个地方时,InvocationHandler的invoke方法中的第一个参数(Object proxy)是什么作用,从字面上来说是代理对象,那么mehtod.invoke(proxy,args)会造成stackOverflow呢?

/**
 * 一个代理实现
 */
 /**
 * 模拟一个代理实现
 */
public class ProxyTest3{

    public interface Interface {
        void print();
    }
    public class A implements Interface {
        @Override
        public void print() {
            System.out.print("AAAAAAAAAA");
        }
    }
    public class B implements Interface {
        @Override
        public void print() {
            System.out.print("BBBBBBBB");
        }
    }

    public Object createProxy(Class cla) {
        return (T)Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //method.invoke(proxy,args);
                return null;
            }
        });
    }

    public static void main(String[] args) throws IOException {
        ProxyTest3 p = new ProxyTest3();
        Interface i = (Interface) p.createProxy(A.class);
        //会死循环
        i.print();
    }
}


执行上线的代码会出现JDK动态代理的学习与理解之:invoke方法为什么不能method.invoke(proxy,args[])_第1张图片
那么是为什么会出现这种情况呢?

答案在代理类中,我们上述的代码Interface i = (Interface) p.createProxy(A.class); 此处的 i 获取到的其实是一个extends Proxy implements Interface的代理类(代理的核心实现就是通过目标对象类的字节码来重新生成一个类对象),生成的代理类如下:

//此处类的结构就是extends Proxy implements 指定接口
//从这个地方也能 明白为什么jdk代理只能代理接口(因为Java是单继承,而jdkProxy生成的代理类对象必然会继承Proxy,因此,只能代理接口)
//不过如果是一个无实现接口无继承类的类,调用Proxy.newProxyInstance,会生成一个extends Proxy implements 自身的一个代理类,但在实际的使用中,这样的类是无法转换成我们想要的东西的,且也无法使用(没发进行方法调用的)
public final class class extends Proxy implements Interface {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public class(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void print() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.ydj.netty.proxy.ProxyTest3$Interface").getMethod("print");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

看到这个地方,问题就迎刃而解了,`

        /**
             * 为什么method.invoke(第一个参数不能是入参的proxy)
             * 首先proxy是代理类的对象,代理类中的方法的实现是
             *     public final void printaa(String var1) throws  {
             *         try {
             *             super.h.invoke(this, m3, new Object[]{var1});
             *         } catch (RuntimeException | Error var3) {
             *             throw var3;
             *         } catch (Throwable var4) {
             *             throw new UndeclaredThrowableException(var4);
             *         }
             *     }
             *   此处的method是接口的抽象方法,如果实现类为代理类的话
             *   比如此时的方法名是:printaa,proxy.printaa的实现是是h.invoke,然后h.invoke又进来,就会实死循环
             */`

你可能感兴趣的:(spring,设计模式,Java,java)