Java SDK动态代理类怎么调用到invoke()方法?

Java SDK动态代理的demo代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKDynamicProxyDemo {
    static interface Iservice {
        void sayHello();
    }

    static class Service implements Iservice {
        @Override
        public void sayHello() {
            System.out.println("say hello~~~~~");
        }
    }

    static class JDKInvocationHandler implements InvocationHandler {
        //被代理对象
        private Object object;

        public JDKInvocationHandler(Object object) {
            this.object = object;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before--say hello");
            Object invoke = method.invoke(object, args);
            System.out.println("after--say hello");
            return invoke;
        }

        /**
         * 生成代理类对象
         *
         * @return
         */
        public Object newProxyInstance() {
            return Proxy.newProxyInstance(
                    object.getClass().getClassLoader(),
                    object.getClass().getInterfaces(),
                    this);
        }
    }
}

main函数测试:

public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        JDKInvocationHandler jdkInvocationHandler = new JDKInvocationHandler(new Service());
        Iservice service = (Iservice) jdkInvocationHandler.newProxyInstance();
        service.sayHello();
    }

以上代码通过System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");来获得运行期生成的代理对象类,运行主函数,会生成一个文件夹,同时该文件夹下有代理对象类,如下:
在这里插入图片描述

$Proxy0.class文件详情如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.example.springboot.codedemo.JDKDynamicProxyDemo.Iservice;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements Iservice {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(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 sayHello() 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.example.springboot.codedemo.JDKDynamicProxyDemo$Iservice").getMethod("sayHello");
            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());
        }
    }
}

抓住问题重点分析,首先看下$Proxy0类的构造方法,如下:

  public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

会发现构造函数的参数是InvocationHandler类实例,而实际上的构造方法却是父类Proxy的构造方法,看看Proxy对应的构造方法,如下:

protected InvocationHandler h;

protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

其实就是简单的对属性InvocationHandler做了个赋值,那么接下来看看$Proxy0类中和我们定义的接口中相同方法签名的方法sayHello(),如下:

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

然后很惊喜的发现里面有个貌似熟悉的调用逻辑:

super.h.invoke(this, m3, (Object[])null)

从代码字面上看,是调用父类的InvocationHandler类实例h,然后再调用h的invoke()方法,所以这里只需要证明h调用的invoke()方法,就是我们构建的InvocationHandler类的实现类的invoke()方法即可。

先看看创建出代理对象的方法,如下:

 public Object newProxyInstance() {
            return Proxy.newProxyInstance(
                    object.getClass().getClassLoader(),
                    object.getClass().getInterfaces(),
                    this);
        }

记住上面关键的参数this,这代表着当前类的实例,这里也就是JDKInvocationHandler类实例,继续跟到newProxyInstance()方法中,抽出其中几个证明的关键方法步骤,如下:

//第一步.创建出代理类
Class<?> cl = getProxyClass0(loader, intfs);
//第二步.拿到代理类的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
//第三步.通过构造函数创建出代理对象
return cons.newInstance(new Object[]{h});

来理一理,首先创建出的是代理对象$Proxy0类,然后拿到该类的构造函数,如下:

public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

接着调用该构造函数生成实例,那么关键点来了,参数h是什么,通过以下截图与之前的新建代理对象的方法对比:
在这里插入图片描述
可以发现h就是this,而this是什么,是我们构建的JDKInvocationHandler类实例,所以$Proxy0类通过构造函数,为父类设置上了它的InvocationHandler类属性,为JDKInvocationHandler类实例,所以动态代理类调用它的sayHello()方法,其实是在调用JDKInvocationHandler类实例的invoke()方法。

总结

Java SDK动态代理的流程大致是这样的,先参照着被代理类的类加载器以及接口构建出代理类,当然这时还只是个类,还不是实例,所以接着要拿到该类的构造函数,然后把我们自己定义的InvocationHandler类的实现类作为构造参数,创建出动态代理类,其实这里真正调用的是Proxy的构造方法,最后返回动态代理实例。所以开发者如果调用动态代理实例的方法,实际上最后会定位到开发者自己实现的InvocationHandler类子类中的invoke()方法,形成闭环。

猜你喜欢

转载自blog.csdn.net/weixin_38106322/article/details/107644783