Retrofit源码学习之动态代理

我们已经知道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 create(final Class 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调用。

你可能感兴趣的:(Retrofit源码学习之动态代理)