动态代理与静态代理 原理剖析

代理模式:
  所谓代理模式,就是通过代理方法来操作目标对象,而不是自己调用。
  代理又分为静态代理动态代理。静态代理和动态代理的区别就是:一个是静态的,一个是动态的,静态代理需要手动编写代理对象让他实现接口,所以最终得到的代理对象的类是确定的。而动态代理让程序在运行的时候自动在内存中通过反射创建一个实现 接口的代理。

怎么能体现:
举个手机的例子:
静态代理需要以下接口和类:

  • 手机接口:MobilePhone(有一个打电话的方法)
  • 实现手机接口的安卓手机:AndroidMobilePhone(implements MobilePhone,实现打电话的方法)
  • 安卓手机的代理对象:AndroidMobileStaticProxyPhone (implements MobilePhone,需要一个局部变量–目标对象)
// 代理对象
public class AndroidMobileStaticProxyPhone implements MobilePhone{
    private MobilePhone amp;
    public AndroidMobileStaticProxyPhone(MobilePhone mobilePhone) {
        this.amp = mobilePhone;
    }
    @Override
    public void call() {
        System.out.println("before call....");
        amp.call();
        System.out.println("after call....");
    }
}

使用:

public static void main(String[] args) {
    // 使用静态代理
    // 1、原始对象
    MobilePhone mp1 = new AndroidMobilePhone("Jack","20");
    // 2、直接new出来代理对象,参数是原始对象
    AndroidMobileStaticProxyPhone amsp = new AndroidMobileStaticProxyPhone(mp1);
    amsp.call();
    System.out.println(amsp.getClass());
}

执行结果:
//class cn.ziwei.proxy.AndroidMobileStaticProxyPhone

动态代理需要以下接口和类:

  • 手机接口:MobilePhone(有一个打电话的方法)
  • 代理实例的调用处理类:MobilePhoneHandler(implements InvocationHandler,有一个局部遍历–目标对象)
// MobilePhoneHandler 
public class MobilePhoneHandler implements InvocationHandler {
    private MobilePhone target;// 目标对象
    public MobilePhoneHandler(MobilePhone target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before call....");
        Object obj = method.invoke(target, args);
        System.out.println("after call....");
        return obj;
    }
}

使用:

public static void main(String[] args) {
    // 使用动态代理
    // 1、原始对象
    MobilePhone mp = new AndroidMobilePhone("Jack","20");
    // 2、代理实例的调用处理类
    MobilePhoneHandler handler = new MobilePhoneHandler(mp);
    // 3、通过Proxy.newProxyInstance创建代理对象 
    Class<? extends MobilePhone> cls = mp.getClass();
    MobilePhone obj = (MobilePhone) Proxy.
            newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), handler);
    obj.call();
    System.out.println(obj.getClass());
    }

结果:

//class com.sun.proxy.$Proxy0

对比两个代理对象的结果:
静态代理:class cn.ziwei.proxy.AndroidMobileStaticProxyPhone
动态代理:class com.sun.proxy.$Proxy0
就能看出来,静态代理的代理对象就是一开始手动写好的那个类,是编译器就确定的。而动态代理生成对对象是运行期产生的是不一定的。 通过反编译 ,看到代理对象如下:

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

package com.sun.proxy;

import ...

public final class $Proxy0 extends Proxy implements MobilePhone {
    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 void call() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("cn.ziwei.proxy.MobilePhone").getMethod("call");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

从代理对象通过反编译 的字节码对象可以看出:
  动态代理类也是实现MobilePhone 接口的,也实现了call方法。并且重写了equals,toString,hashCode方法。

再解释以下:
动态代理里面生成代理对象的:Proxy. newProxyInstance
源码里面,发现真正返回代理对象的是:

Class<?> cl = getProxyClass0(loader, intfs);

跟进去,里面起作用的是

// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);

注释的意思是:如果实现给定接口的给定加载器的代理对象存在,就直接返回缓存的副本,否则,将会通过Proxy类的ProxyClassFactory方法,创造proxy对象。
跟进去,里面起作用的是:

/*
 * Generate the specified proxy class.
 */
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    proxyName, interfaces, accessFlags);

跟进去,发现在main方法里设置以下值,会保存代理对象的字节码对象

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

OOK。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值