动态代理原理解析

1.什么是动态代理?

2.动态代理中Proxy.newProxyInstance()究竟做了什么?

3.最终的动态代理类$Proxy0是如何生成的?

4.public Object invoke(Object o, Method method, Object[] objects)这三个参数都代表了什么含义?

1.动态代理:我认为是动态生成一个代理类,然后在这个代理类中,执行被代理类中需要执行的方法。

我们先看一个demo:

//接口
public interface ArtSubject {
     String singing(String name);
}
//真实角色:
public class RealSubject implements ArtSubject {
    @Override
    public String singing(String name) {
        System.out.println("我要唱一首歌,歌名为:"+name);
        return name;
    }
}
//代理角色
public class DynamicSubject implements InvocationHandler {
    private Object sub; 
    public DynamicSubject(Object object){
        this.sub = object;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("唱歌前喝点酒!");
        Object object = method.invoke(sub,objects);//通过反射调用singing()方法
        System.out.println("唱完歌睡觉。" );
        return object;
    }
}
public class Test {

    public static void main(String[] args){

// 将我们生成的代理类写到项目跟目录com/sun/proxy/$Proxy0.class
//有兴趣可以去看ProxyGenerator这个类
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        RealSubject realSubject = new RealSubject();
        DynamicSubject subject = new DynamicSubject(realSubject);

        ArtSubject o = (ArtSubject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),        realSubject.getClass().getInterfaces(), subject);
        o.singing("《酒干倘卖无》");
    }
}

打印:

唱歌前喝点酒!
我要唱一首歌,歌名为:《酒干倘卖无》
唱完歌睡觉。

现在我们可以看到,我们可以在不改变真实角色代码的情况下,通过代理的方式,执行了真实角色中想要执行的方法并且在真实角色要想要执行的方法--“唱歌”前或后,添加额外想执行的动作。

2.那么Proxy.newProxyInstance()究竟做了什么呢?

1)参数一:类加载器(用于加载最后生成的$Proxy0类)。

2)参数二:真实角色实现的接口(代理只能对接口类进行代理,所以必须的有接口,否则不能通过验证)。

3)参数三:InvocationHandler,在这里就是实现了InvocationHandler的DynamicSubject类。

看源码Proxy.newProxyInstance(),其中调用了getProxyClass0(var0, var3)方法,返回一个class,最后根据这个class返回一个实例。

/*
 * Look up or generate the designated proxy class.
 */
Class<?> cl = getProxyClass0(loader, interfaces);

我们再进去看getProxyClass0()方法,我们注意到下面部分代码:

{
    // Android-changed: Generate the proxy directly instead of calling
    // through to ProxyGenerator.
    List<Method> methods = getMethods(interfaces);//获取接口里面的方法
    Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);//将方法进行排序
    validateReturnTypes(methods);
    List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);

    Method[] methodsArray = methods.toArray(new Method[methods.size()]);
    Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

    /*
     * Choose a name for the proxy class to generate.
     */
    final long num;
    synchronized (nextUniqueNumberLock) {
        num = nextUniqueNumber++;
    }
    String proxyName = proxyPkg + proxyClassNamePrefix + num;//拼接$Proxy0代理类名称

    //最后调用native方法生成代理类
    proxyClass = generateProxy(proxyName, interfaces, loader, methodsArray,exceptionsArray);
}

下面就是我们最终生成的$Proxy0类:

public final class $Proxy0 extends Proxy implements ArtSubject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    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 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 String singing(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            //通过反射拿到singing()方法
            m3 = Class.forName("DynamicProxyPart.ArtSubject").getMethod("singing", Class.forName("java.lang.String"));
            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类实现了ArtSubject接口,当我们调用o.singing("《酒干倘卖无》");,实际上调用的是代理类$Proxy0中的方法 public final String singing(String var1) throws{},其中的super.h中的h代表了保存在父类(Proxy.class)中的InvocationHandler,super.h.invoke(this, m3, new Object[]{var1}),其实就是在调用实现类DynamicSubject中的invoke()方法,并且把第一个参数:this-$Proxy0,第二个参数:通过反射得到的方法singing(String var1),第三个参数:singing(String var1)中的参数var1,传给DynamicSubject中的invoke(Object o, Method method, Object[] objects)方法中,最后我们在该方法中通过反射调用singing(string args)方法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值