设计模式之代理模式

代理模式分为静态代理和动态代理

静态代理

就拿网络请求来说
先定义一个网络请求统一接口INetworkRequester 里面有一个post方法

public interface INetworkRequester{
	void post();
}

网络请求框架有很多种比如早期的 Volley 现在的Okhttp

public class OkhttpNetworkRequester implements INetworkRequester{
	public void post(){
		Log.i("ancely_proxy","OkhttpNetworkRequester.post()");
	}
}

public class VolleyNetworkRequester implements INetworkRequester{
	public void post(){
		Log.i("ancely_proxy","VolleyNetworkRequester.post()");
	}
}

在请求网络的时候有一个代理的网络请求器,在请求网络的时候我们并不关心里面是怎么请求的,只要能达到目的就可以

public class ProxyNetworkRequester implements INetworkRequester{
	private INetworkRequester mRequester;
	public ProxyNetworkRequester(INetworkRequester requester){
		mRequester = requester;
	}
	public void post(){
		mRequester.post();
	}

}

假如我们一开始使用的是Volley请求库,我们只需要这样调用

INetworkRequester requester = new ProxyNetworkRequester(new VolleyNetworkRequester());
requester.post();//这样用的就是Volley框架

//后面更新迭代,Volley不受欢迎,Okhttp流行起来了我们要换库就非常的方便
INetworkRequester requester = new ProxyNetworkRequester(new OkhttpNetworkRequester());
requester.post();//这样用的就是Okhttp框架

当然比如常用的Json序列化库也可以同样操作

动态代理

动态代理使用起来其实很简单,主要是调用Proxy的newProxyInstance方法

INetworkRequester requester = new ProxyNetworkRequester(new VolleyNetworkRequester());
Object proxyInstance = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{INetworkRequester.class}, (o, method, objects) -> {
    Log.i("ancely_proxy","newProxyInstance.post()");
    return method.invoke(requester,objects);
});
INetworkRequester requester1 = (INetworkRequester) proxyInstance;
Log.i("ancely_proxy","proxyInstance hashCode: ."+ requester1.hashCode());
requester1.post();

动态代理原理

  • 类的完整生命周期
    Java源文件---->编译生成java字解码.class文件(实实在在的文件)---->通过类加载机制变成Class对象----->然后再实例化出对象—>卸载

  • 动态代理的class对象是怎么来的

    • 逻辑在Proxy的newProxyInstance里
    • 通过Proxy里的getProxyClass0方法创建了一个Class对象cl,怎么生成的我们不关心
    • 获取Class对象的构造方法cl.getConstructor(constructorParams);
    • 反射创建对象cons.newInstance(h);h就是我们newProxyInstance方法里传进定数的InvocationHandler接口
      源码如下
private static final Class<?>[] constructorParams = new Class[]{InvocationHandler.class};
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) {
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        //创建了一个Class对象
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
        		//获取到构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                cons.setAccessible(true);
            }
            //通过构造方法实例出对象,
            return cons.newInstance(h);
        } catch (Exception e) {
            throw new InternalError(e.toString(), e);
        } 
    }

内存中生成的Class是什么样的,通过以下方法可以获取

String name = INetworkRequester.class.getName() + "$Proxy0";
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{INetworkRequester.class});
try {
    FileOutputStream fos = new FileOutputStream("complier/" + name + ".class");
    fos.write(bytes);
    fos.close();
} catch (Exception e) {
    e.printStackTrace();
}
package com.ancely.complier;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class INetworkRequester$Proxy0 extends Proxy implements INetworkRequester {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
    public INetworkRequester$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 post() 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.ancely.complier.INetworkRequester").getMethod("post");
            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());
        }
    }
}

通过上面文件就非常清楚动态代理的原理了

  • 1.通过Proxy.newProxyInstance创建了一个Object对象 proxyObject
  • 2.通过生成的文件可以发现 proxyObject是继承了Proxy 实现了代理接口INetworkRequester
  • 3.在生成的Class文件的构造方法中传入了我们在newProxyInstance方法中传入了InvocationHandler参数,
  • 4.所以生成的Class文件执有了一个InvocationHandler h
  • 5.当我们调用了proxyObject对应的方法时就会调用InvocationHandler h的invoke方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值