首先,什么是动态代理和为什么会有动态代理。
众所周知,Java 是一门静态语言,编写完的类,无法在运行时做动态修改。
一个简单的动态代理如下:
1、先定义一个接口,想要使用动态代理,必须先定义一个接口:
1public interface IHello{
2 void hello();
3}
2、再让想要动态代理的类实现接口:
1public class Hello implements IHello{
2 public void hello(){
3 System.out.print("hello");
4 }
5}
3、再定义一个实现InvocationHandler
的类:
1public class MyInvocationHandler implements InvocationHandler{
2 private Object obj;
3 public MyInvocationHandler(Object obj){
4 this.obj = obj;
5 }
6 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
7 //在原方法前边动态插入代码
8 Object result = method.invoke(target, args);
9 //在原方法后边动态插入代码
10 return result;
11 }
12}
InvocationHandler
是 Java 提供的动态代理实现类,想要使用动态代理,必须实现该接口,重写invoke
方法,并酌情在原方法的前边或后边插入需要的代码,method.invoke(target, args)
会调用原方法(比如 Hello
类中的 hello()
方法)。
上边就是一个简单的动态代理的例子。
Retrofit 中也使用了动态代理,我们以官方提供的示例代码为例,首先声明一个接口:
1public interface GitHubService {
2 @GET("users/{user}/repos")
3 Call<List<Repo>> listRepos(@Path("user") String user);
4}
然后在需要网络请求的地方调用如下代码:
1Retrofit retrofit = new Retrofit.Builder()
2 .baseUrl("https://api.github.com/")
3 .build();
4
5GitHubService service = retrofit.create(GitHubService.class);
6
7Call<List<Repo>> repos = service.listRepos("octocat");
上边定义的GithubService
等同于前文的IHello
接口,一个类想要做动态代理,就必须先要定义一个接口。
然后关键代码是retrofit
,表面上看这与上文提到的写法完全对应不上,其实这里只是封装起来了,查看它的源码就能发现端倪。
1public <T> T create(final Class<T> service) {
2 Utils.validateServiceInterface(service);
3 if (validateEagerly) {
4 eagerlyValidateMethods(service);
5 }
6 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
7 new InvocationHandler() {
8 private final Platform platform = Platform.get();
9
10 @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
11 throws Throwable {
12 // If the method is a method from Object then defer to normal invocation.
13 if (method.getDeclaringClass() == Object.class) {
14 return method.invoke(this, args);
15 }
16 if (platform.isDefaultMethod(method)) {
17 return platform.invokeDefaultMethod(method, service, proxy, args);
18 }
19 ServiceMethod<Object, Object> serviceMethod =
20 (ServiceMethod<Object, Object>) loadServiceMethod(method);
21 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
22 return serviceMethod.adapt(okHttpCall);
23 }
24 });
25 }
看到new InvocationHandler(){****}
了吧,等于变相实现了InvocationHandler
,另外,Proxy.newProxyInstance
最终会调用一个 native 方法,动态生成一个 GitHubService
(我们前文声明的接口)的实现类,大致长这样(这是 Java 动态生成的,所以以下代码并不完全准确):
1 public final class $Proxy0 extends Proxy implements GitHubService {
2 private static Method m1;
3 private static Method m0;
4 private static Method m3;
5 private static Method m2;
6
7 static {
8 try {
9 m1 = Class.forName("java.lang.Object").getMethod("equals",
10 new Class[] { Class.forName("java.lang.Object") });
11
12 m0 = Class.forName("java.lang.Object").getMethod("hashCode",
13 new Class[0]);
14
15 m3 = Class.forName("***.GitHubService").getMethod("request",
16 new Class[0]);
17
18 m2 = Class.forName("java.lang.Object").getMethod("toString",
19 new Class[0]);
20
21 } catch (NoSuchMethodException nosuchmethodexception) {
22 throw new NoSuchMethodError(nosuchmethodexception.getMessage());
23 } catch (ClassNotFoundException classnotfoundexception) {
24 throw new NoClassDefFoundError(classnotfoundexception.getMessage());
25 }
26 }
27
28 public $Proxy0(InvocationHandler invocationhandler) {
29 super(invocationhandler);
30 }
31
32 @Override
33 public final boolean equals(Object obj) {
34 try {
35 return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
36 } catch (Throwable throwable) {
37 throw new UndeclaredThrowableException(throwable);
38 }
39 }
40
41 @Override
42 public final int hashCode() {
43 try {
44 return ((Integer) super.h.invoke(this, m0, null)).intValue();
45 } catch (Throwable throwable) {
46 throw new UndeclaredThrowableException(throwable);
47 }
48 }
49
50 public final void listRepos() {
51 try {
52 super.h.invoke(this, m3, null);
53 return;
54 } catch (Error e) {
55 } catch (Throwable throwable) {
56 throw new UndeclaredThrowableException(throwable);
57 }
58 }
59
60 @Override
61 public final String toString() {
62 try {
63 return (String) super.h.invoke(this, m2, null);
64 } catch (Throwable throwable) {
65 throw new UndeclaredThrowableException(throwable);
66 }
67 }
68}
可以发现 Java 帮我们生成的类中重写了我们GithubService
接口的listRepos()
,该方法中会调用super.h.invoke(this, m3, null);
,就是调用父类的h
的invoke()
,它的父类是Proxy
,h
是一个InvocationHandler
对象;
1/**
2* the invocation handler for this proxy instance.
3* @serial
4*/
5protected InvocationHandler h;
这个h
,就是上文提到的new InvocationHandler(){}
;
1public <T> T create(final Class<T> service) {
2 Utils.validateServiceInterface(service);
3 if (validateEagerly) {
4 eagerlyValidateMethods(service);
5 }
6 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
7 new InvocationHandler() {
8 private final Platform platform = Platform.get();
9
10 @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
11 throws Throwable {
12 // If the method is a method from Object then defer to normal invocation.
13 if (method.getDeclaringClass() == Object.class) {
14 return method.invoke(this, args);
15 }
16 if (platform.isDefaultMethod(method)) {
17 return platform.invokeDefaultMethod(method, service, proxy, args);
18 }
19 ServiceMethod<Object, Object> serviceMethod =
20 (ServiceMethod<Object, Object>) loadServiceMethod(method);
21 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
22 return serviceMethod.adapt(okHttpCall);
23 }
24 });
25 }
最后,简单画一个图总结下流程: