【Android】动态代理在 Retrofit 中的使用

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

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

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

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

1
2
3
public interface IHello{
void hello();
}

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

1
2
3
4
5
public class Hello implements IHello{
public void hello(){
System.out.print("hello");
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
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(target, args);
//在原方法后边动态插入代码
return result;
}
}

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

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

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

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

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

1
2
3
4
5
6
7
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,表面上看这与上文提到的写法完全对应不上,其实这里只是封装起来了,查看它的源码就能发现端倪。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 动态生成的,所以以下代码并不完全准确):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  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对象;

1
2
3
4
5
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
}
});
}

最后,简单画一个图总结下流程:

retrofit.jpg