0%

动态代理 yyds

前言

从代理模式出发,逐步探索 Retrofit 的奥秘

代理模式

代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。

静态代理

关于静态代理本身的实现就很简单了,这里可以简单看一下实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IFooDao {
void doSomething();
}

public class IFooDaoImpl implements IFooDao {
@Override
public void doSomething() {
System.out.println(this.getClass().getName() + " work");
}
}

public class IFooDaoProxy implements IFooDao {
private IFooDao mIFooDao;

public IFooDaoProxy(IFooDao mIFooDao) {
this.mIFooDao = mIFooDao;
}

@Override
public void doSomething() {
this.mIFooDao.doSomething();
}
}

依次创建了服务接口、服务实现、服务代理

1
2
3
4
5
6
public class Client {
public static void main(String[] args) {
IFooDao prox = new IFooDaoProxy(new IFooDaoImpl());
prox.doSomething();
}
}

静态代理本身的实现很简单,其中涉及到的类也会比较明确。这里需要注意的是,服务接口的实现不一定通过定义 接口类的方式实现(即不一定是 interface ),抽象类也是一种选择,比如 Android 中的 Activity 为了实现在不通过版本的兼容性,就是采用了 AppCompatDelegate 这个抽象类。Activity 本身并不负责实现 setContentView() 之类的功能。而是将其代理给 AppCompatDelegate 的实现类 AppCompatDelegateImpl

动态代理

可以看到,在静态代理中,代理类需要提前创建,而通过动态代理,就可以在运行期实现创建代理类的效果。

依次定义接口和注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface IFooDao {
void doSomething();

@FakeProxy("proxy is yyds")
int add(@EasyProxy String a, @Nullable String b);
}

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface EasyProxy {
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FakeProxy {
String value() default "";
}

上面定义了接口和 EasyProxyFakeProxy 两个注解。

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
    private static void dynamicProxy(IFooDao realDao) {
IFooDao proxy = (IFooDao) Proxy.newProxyInstance(
realDao.getClass().getClassLoader(),
realDao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("proxy=%s,method=%s,args=%s\n",
proxy.getClass().getSimpleName(), method.getName(), Arrays.toString(args));

System.out.println(method.getGenericReturnType());
System.out.println(Arrays.toString(method.getAnnotations()));
System.out.println(Arrays.toString(method.getGenericParameterTypes()));
System.out.println(Arrays.deepToString(method.getParameterAnnotations()));

// any-operation-before invoke
Object object = method.invoke(realDao, args);
// any-operation-after invoke
System.out.println("========================");
return object;
}
}
);
proxy.doSomething();
proxy.add("1", "2");
}


public class IFooDaoImpl implements IFooDao {
@Override
public void doSomething() {
System.out.println(this.getClass().getName() + " work");
}

@Override
public int add(@EasyProxy String a, @Nullable String b) {
return Integer.parseInt(a) + Integer.parseInt(b);
}
}

// main
dynamicProxy(new IFooDaoImpl());

可以看到,利用 Java 系统提供的 Proxy 静态方法 newProxyInstance ,只需要提供 IFooDao 的一个具体实现,那么就可以返回一个代理类,通过这个代理类 proxy 就可以访问 IFooDao 中定义的接口了。

可以看一下输出

1
2
3
4
5
6
7
8
9
10
11
12
13
proxy=$Proxy0,method=doSomething,args=null
void
[]
[]
[]
com.dp.internal.proxy.IFooDaoImpl work
========================
proxy=$Proxy0,method=add,args=[1, 2]
int
[@com.dp.internal.proxy.FakeProxy(value=proxy is yyds)]
[class java.lang.String, class java.lang.String]
[[@com.dp.internal.proxy.EasyProxy()], []]
========================

可以看到在 InvocationHandlerinvoke 方法中,我们通过 method 可以获取到关于当前 method 的所有信息,包括其参数、方法注解、参数注解等信息。这里值得注意的是 invoke 方法是有返回值的。

Retrofit

关于动态代理,Android 中使用最有名的莫过于 Retrofit 框架的实现了。下面就来看看 Retrofit 是如何使用动态代理的。

以下分析基于 com.squareup.retrofit2:retrofit:2.9.0

Retrofit 到底做了什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface ApiService {

@GET("wxarticle/chapters/json")
fun getAccountList(): Call<WeChatCountList>

@GET("wxarticle/chapters/json")
fun getAccountJson(): Call<ResponseBody>

@GET("wxarticle/chapters/json")
fun getWeChatAccountList(): Observable<WeChatCountList>
}

fun go2() {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
val service = retrofit.create(ApiService::class.java)

val call = service.getAccountJson()
}

这里需要注意的是,ApiService 中定义的前两个方法返回值都是 Call 类型的。getWeChatAccountList 返回的是 Observable 类型。但这对于 Retrofit 整体的实现来说是没有什么大的区别的,无非只是多了一个 CallAdapter ,需要把 Call 执行的结果用 Observeable 进行一次包装。使用 Retrofit 的本质还是为了发起网络请求,对于网络请求来说最重要的是通过 OkHttp 创建 Call 的实现。因此,从这个视角出发再去看 Retrofit 的实现就会发现他其实简单。

Retrofit build

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
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}

okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// 在 Android 上,这个 Executor 就是主线程
callbackExecutor = platform.defaultCallbackExecutor();
}

// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
// 除了在 build 过程中添加的自定义 CallAdapter,还要添加系统默认的 Adapter 。
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
// 内置的 Converter 主要是对返回的 Response 进行再次处理
converterFactories.add(new BuiltInConverters());
// build 阶段自定义添加的 Converter
converterFactories.addAll(this.converterFactories);
// 如果支持 Java,会添加支持 Optional 操作的 Converter
converterFactories.addAll(platform.defaultConverterFactories());

return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}

Retrofit 最核心的两个接口就是 CallAdapterConverter

CallAdapter
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

/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is {@linkplain
* Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit} instance.
*/
public interface CallAdapter<R, T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type is
* used to prepare the {@code call} passed to {@code #adapt}.
*
* <p>Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();

/**
* Returns an instance of {@code T} which delegates to {@code call}.
*
* <p>For example, given an instance for a hypothetical utility, {@code Async}, this instance
* would return a new {@code Async<R>} which invoked {@code call} when run.
*
* <pre><code>
* &#64;Override
* public &lt;R&gt; Async&lt;R&gt; adapt(final Call&lt;R&gt; call) {
* return Async.create(new Callable&lt;Response&lt;R&gt;&gt;() {
* &#64;Override
* public Response&lt;R&gt; call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
T adapt(Call<R> call);

/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);

/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}

/**
* Extract the raw class type from {@code type}. For example, the type representing {@code
* List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
Converter
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

/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;

/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}

/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}

/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
* {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
* QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}

/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}

/**
* Extract the raw class type from {@code type}. For example, the type representing {@code
* List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}

  • CallAdapter 顾名思义,就是把 OkHttp 的 Call 通过适配器转换成任意我们在接口方法中声明的返回类型,比如 Observeable .如果没有添加 自定义的 CallAdapter ,Retrofit 默认返回的就是 Call 类型的 Call. 那么其中的 T 又是怎么决定的呢?这就要靠 Converter 了。OkHttp 默认返回的是 Call<ResponseBody>
  • Converter 就是对返回的 ResponseBody 进行类型转换,比如我们非常熟悉的 addConverterFactory(GsonConverterFactory.create()) .这个转换器具体是用什么库实现 json 到 object 的转换,对于 Retrofit 来说并不重要。

对于 Retrofit 来说,上述两个转换器内部的实现完全是透明的,Retrofit 真是按责任链模式,将数据一层层的传递给 callAdapterFactoriesconverterFactories 中剩余的转换器,直到全部消费完成。

那么这个过程具体是怎么展开的呢?下面就从 Retrofit 的创建展开分析。

Retrofit create 到底创建了啥?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];

@Override
public @Nullable 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);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}

create 方法总结起来很简单,就是创建了传入的 service 这个类的一个动态代理。这里就是有意思的地方了,我们知道在 Java 中 interface 类型的类是无法创建实例的,比如 ApiService 这个接口,我们可以通过创建匿名类的方式实现这个接口,但是那样需要在实现接口的地方实现其所有方法的及其细节,这显然不是我们想要的。

而 Retrofit 通过动态代理,相当于是动态持有了接口实现的引用,而当我们单独调用接口中的每一个方法时,便会触发其 invoke 方法,在这个方法中通过 method 参数可以获取到当前调用方法的所有信息,通过这些信息就可以实现方法的具体细节了。可以说 Retrofit 的设计非常巧妙,利用接口完全解耦了定义和实现。

Retrofit 实现细节

1
2
3
4
5
6
7
8
9
fun go2() {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
val service = retrofit.create(ApiService::class.java)
println("service is $service")
println("service is ${service.javaClass.name}")
val call = service.getAccountJson()
}

我们通过 create 创建了 ApiService 的实例。那么 service 到底是什么呢?我们可以看一下

1
2
service is retrofit2.Retrofit$1@14d3bc22
service is com.sun.proxy.$Proxy0

可以看到这个实例的 Class 类型是 com.sun.proxy.$Proxy0 。这个类型其实就是 InvocationHandler 中 invoke 方法的第一个参数 Object 的类型。

再看调用链,当我们调用 service.getAccountJson() 方法时

可以看到通过动态代理会调用到 invoke 方法中,最终会调用 loadServiceMethod(method).invoke(args) 方法。

Retrofit 只有默认 CallAdapter 和 Converter 时的执行流程。

可以说 Retrofit 的整体设计非常的巧妙。

参考文档

加个鸡腿呗.