Retrofit源码学习之动态代理

来源:互联网 发布:大学的意义知乎 编辑:程序博客网 时间:2024/04/30 07:07

我们已经知道retrofit的主要作用是把一个接口解析包装成http的请求,由OKhttp发送。用到的技术就是动态代理。动态代理的作用就是当你要调用某个Class的方法前或后,插入你想要执行的代码。接下来我们看一下如何实现动态代理。
一、定义接口:

public interface UserListener {    String getName();    int getAge();}

二、创建该接口的实现类

public class User implements UserListener {    @Override    public String getName() {        return "哈哈哈";    }    @Override    public int getAge() {        return 18;    }}

三、创建动态代理类并实现InvocationHandler接口,该接口只包含一个方法,之后再讲解它

public Object invoke(Object proxy, Method method, Object[] args)        throws Throwable;

动态代理类:

public class MyInvocationHandler implements InvocationHandler {    private Object target;    public MyInvocationHandler(Object target){        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if(method.getName().equals("getName")){            String result = (String) method.invoke(target,args);            return result+"嘿嘿嘿";        }else {            int age = (int) method.invoke(target,args);            return age+10;        }    }}

四、使用动态代理类:

UserListener user = new User();        MyInvocationHandler handler = new MyInvocationHandler(user);        UserListener proxy = (UserListener) Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),handler);        Log.d("proxy",proxy.getName());        Log.d("proxy",proxy.getAge()+"");

结果:

03-11 13:05:22.631 30332-30332/com.yjs.okhttp D/proxy: 哈哈哈嘿嘿嘿03-11 13:05:22.641 30332-30332/com.yjs.okhttp D/proxy: 28

解析
首先看一下InvocationHandler中的方法,

public Object invoke(Object proxy, Method method, Object[] args)        throws Throwable;

Object proxy:指代我们所代理的那个真实对象
Method method:指代的是我们所要调用真实对象的某个方法的Method对象
Object[] args:指代的是调用真实对象某个方法时接受的参数

接下来再看一下Proxy类中的newProxyInstance方法:

 public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException

ClassLoader loader:定义了由哪个ClassLoader对象来对生成的代理对象进行加载

Class<?>[] interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

InvocationHandler h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

最后看一下Retrofit中的创建方法:

 ApiStores apiStores = ApiClient.retrofit().create(ApiStores.class);
public <T> T create(final Class<T> service) {    Utils.validateServiceInterface(service);    if (validateEagerly) {      eagerlyValidateMethods(service);    }    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },        new InvocationHandler() {          private final Platform platform = Platform.get();          @Override public Object invoke(Object proxy, Method method, Object... args)              throws Throwable {            // If the method is a method from Object then defer to normal invocation.            if (method.getDeclaringClass() == Object.class) {              return method.invoke(this, args);            }            if (platform.isDefaultMethod(method)) {              return platform.invokeDefaultMethod(method, service, proxy, args);            }            ServiceMethod serviceMethod = loadServiceMethod(method);            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });  }

当我们把包含网络请求接口的类传入到Retrofit的create方法后,就会利用动态代理模式,将接口解析包装成ServiceMethod,再转化成OkHttpCall供OKhttp调用。

0 0
原创粉丝点击