动态代理在 Retrofit 中的使用

首先,什么是动态代理和为什么会有动态代理。

众所周知,Java 是一门静态语言,编写完的类,无法在运行时做动态修改。

一个简单的动态代理如下:

1、先定义一个接口,想要使用动态代理,必须先定义一个接口:

public interface IHello{
    void hello();
}

2、再让想要动态代理的类实现接口:

public class Hello implements IHello{
    public void hello(){
        System.out.print("hello");
    }
}

3、再定义一个实现InvocationHandler的类:

public class MyInvocationHandler implements InvocationHandler{
    private Object obj;
    public MyInvocationHandler(Object obj){
        this.obj = obj;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        //在原方法前边动态插入代码
        Object result = method.invoke(obj, args);
        //在原方法后边动态插入代码
        return result;
    }
}

InvocationHandler是 Java 提供的动态代理实现类,想要使用动态代理,必须实现该接口,重写invoke方法,并酌情在原方法的前边或后边插入需要的代码,method.invoke(target, args)会调用原方法(比如 Hello 类中的 hello()方法)。

上边就是一个简单的动态代理的例子。

Retrofit 中也使用了动态代理,我们以官方提供的示例代码为例,首先声明一个接口:

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

然后在需要网络请求的地方调用如下代码:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

上边定义的GithubService等同于前文的IHello接口,一个类想要做动态代理,就必须先要定义一个接口。

然后关键代码是retrofit,表面上看这与上文提到的写法完全对应不上,其实这里只是封装起来了,查看它的源码就能发现端倪。

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, @Nullable 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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

看到new InvocationHandler(){****}了吧,等于变相实现了InvocationHandler,另外,Proxy.newProxyInstance最终会调用一个 native 方法,动态生成一个 GitHubService(我们前文声明的接口)的实现类,大致长这样(这是 Java 动态生成的,所以以下代码并不完全准确):

  public final class $Proxy0 extends Proxy implements GitHubService {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
  
            m3 = Class.forName("***.GitHubService").getMethod("request",  
                    new Class[0]);  
  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final void listRepos() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
} 

可以发现 Java 帮我们生成的类中重写了我们GithubService接口的listRepos(),该方法中会调用super.h.invoke(this, m3, null);,就是调用父类的hinvoke(),它的父类是Proxyh是一个InvocationHandler对象;

/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;

这个h,就是上文提到的new InvocationHandler(){}

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, @Nullable 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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

最后,简单画一个图总结下流程:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值