JDK动态代理详解

JDK动态代理

准备

被代理类

public class Demo implements DemoInterface{
    @Override
    public int get(int num) {
        return num + 1;
    }
}

代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DemosProxy implements InvocationHandler {
    private Object target;
    public DemosProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法返回开始");
        Object obj = method.invoke(target, args);
        System.out.println("方法返回结束");
        return obj;
    }
}

接口

public interface DemoInterface {
    int get(int num);
}

测试类

import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        DemoInterface demoInterface = (DemoInterface)Proxy.newProxyInstance(DemosProxy.class.getClassLoader(),
                                                     new Class[]{DemoInterface.class}, new DemosProxy(new Demo()));
        int res = demoInterface.get(99);
        System.out.println("res = " + res);
    }
}

基础解释

JDK动态代理是基于接口的动态代理,这与它的实现机制有很大的关系。

原理解释

动态代理的目标是在被代理类方法执行前后添加附加额外操作,更加准确的说是为被代理类扩展额外功能。
1
具体实现

被代理类 - Demo
代理类 - DemosProxy
接口 - DemoInterface
测试类 - Test

1、注意Demo实现DemoInterface接口,而DemosProxy实现InvocationHandler接口。
2、测试类

DemoInterface demoInterface  = (DemoInterface)Proxy.newProxyInstance(DemosProxy.class.getClassLoader(), new Class[]{DemoInterface.class}, new DemosProxy(new Demo()));
int res = demoInterface.get(99);

这段代码中的demoInterface对象实际上是代理类的对象
根据多态性,接口类型引用可以引用其实现类的对象,而这个代理类并非是DemosProxy类,而是JDK动态代理生成的临时类$Proxy0,而这个类又在内部调用DemosProxy的对应的方法,而DemosProxy类又在其内部去调用Demo类的对应方法完成操作。
2
通过观察newProxyInstance方法的底层源码,我们能够得知demoInterface确实是$Proxy对象。

// 获取代理类的构造器。interfaces为DemoInterface,而DemosProxy实现的是
// InvocationHandler接口;$Proxy实现的是DemoInterface接口
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
        Objects.requireNonNull(h);
        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
        return newProxyInstance(caller, cons, h);
    }
    // 根据构造器和参数返回一个对象,这里是$Proxy类构造器,说明返回的是$Proxy类对象。
    private static Object newProxyInstance(Class<?> caller,
                                           Constructor<?> cons,
                                           InvocationHandler h) {
        try {
            if (caller != null) {
                checkNewProxyPermission(caller, cons.getDeclaringClass());
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException | InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        }
    }

给出本人的调试截图,
3
位置在源码的Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);处。
3、 $Proxy0.class

System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

该语句位于测试类方法被调用前,作用是保存$Proxy0.class文件。

低版本的jdk请使用

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

4、使用idea打开这个文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.example.DemoInterface;

public final class $Proxy0 extends Proxy implements DemoInterface {
    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 int get(int var1) throws  {
        try {
            return (Integer)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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("org.example.DemoInterface").getMethod("get", Integer.TYPE);
            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());
        }
    }
}

public final class $Proxy0 extends Proxy implements DemoInterface { 从中可以看出$Proxy类继承Proxy类并实现DemoInterface接口,这与Demo实现的是同一个接口。

public final int get(int var1) throws {部分,能够发现$Proxy内部的方法实现是与DemoInterface接口中的方法绑定的,所以当调用get方法时的对象其实是$Proxy的get()方法。

接下来关注get方法的内部

return (Integer)super.h.invoke(this, m3, new Object[]{var1});

通过idea的辅助,能够得知h的类型为InvocationHandler,而在本类中传入的InvocationHandler对象正好是new DemosProxy(new Demo()),因此$Proxy的get方法调用的是DemosProxy类的invoke方法。

接下来,参数被传递到DemosProxy类的invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法返回开始");
        Object obj = method.invoke(target, args);
        System.out.println("方法返回结束");
        return obj;
    }

参数映射为 this - proxy, m3 - method,new Object[]{var1} - args。
var1=new Object[]{99}

 m3 = Class.forName("org.example.DemoInterface").getMethod("get", Integer.TYPE);

m3证明调用的是DemoInterface接口的get方法,结合Object obj = method.invoke(target, args)的target对象,可以得到,new Demo.get(agrs);的结论。

至此,我们穿过了动态代理实现的全过程。

总结
1、创建$Proxy对象并赋予DemoInterface引用
2、通过demoInterface对象调用$Proxy类的get方法($Proxy类已经绑定DemoInterface接口中的方法)
3、$Proxy类的get方法内部调用DemosProxy的invoke方法
4、invoke方法调用Demo类的get方法

关于为什么要使用/$Proxy类?
请参考连接面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值