Retrofit主流程分析

Retrofit介绍

https://github.com/square/retrofit

Type-safe HTTP client for Android and Java。

根据官方介绍,Retrofit是可用于Android和Java的类型安全的HTTP客户端库。这里解析的是Retrofit 2.4.0版本的代码。

使用方式:

  1. 创建一个interface服务接口包含请求接口合集,使用注解进行配置:

    1
    2
    3
    4
    public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
    }
  2. 使用时获取Retrofit和创建interface实例:

    1
    2
    3
    4
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
    GitHubService service = retrofit.create(GitHubService.class);
  3. 􏰄调用interface具体方法创建:

    1
    Call<List<Repo>> repos = service.listRepos("octocat");
  4. 使用Call.execute()发送同步或者Call.enqueue()发送异步请求:

    1
    repos.enqueue(callback);

Retrofit的创建

和很多其他库一样,Retrofit的创建使用了Builder模式,在此不做赘述。

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
25
26
27
28
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
// 将interface声明的接口方法提前解析并存在serviceMethodCache里
eagerlyValidateMethods(service);
}
// 使用动态代理模式创建interface接口服务实例
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 Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {

if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}

if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}

// 将方法解析并存在serviceMethodCache里
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}

ServiceMethod和HttpServiceMethod

Retrofit里有个serviceMethodCache是存着ServiceMethod的ConcurrentHashMap,ServiceMethod用于解析interface服务里的方法注解, 把对接口方法的调用转为一次HTTP调用。

新版本中,ServiecMethod为抽象类,其实现类为HttpServiceMethod。核心方法是parseAnnotations和invoke方法。

HttpServiceMethod.parseAnnotations()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT>parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 创建CallAdapter,在Retrofit类内部,遍历一个CallAdapter.Factory列表,让工厂们提供
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}

// 创建ResponseConverter,在Retrofit类内部,遍历一个Converter.Factory列表,让工厂们提供
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

// 返回一个HttpServiceMethod
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}

HttpServiceMethod的构造函数几个重要参数作用:

  • RequestFactory:构造HTTP请求,Retrofit基于OKHttp进行封装,最终HTTP请求被抽象为了okhttp3.Call类。
  • okhttp3.Call.Factory:OkHttp创建请求的工厂类。
  • CallAdapter:用于将返回Body转为具体的类型,即将retrofit2.Call转为T。
  • Converter:Converter<ResponseBody, T>类型,负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由ResponseBody封装)转化为T类型的对象。

HttpServiceMethod.invoke()

1
2
3
4
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}

invoke在retrofit的create方法里动态代理中调用,在DefaultCallAdapterFactory里通过callAdapter.adapt将接口转为OkHttpCall。

综上,Retrofit.create()使用动态代理创建了interface实例,通过parseAnnotations将注解定义好的接口方法解析为ServiceMethod,ServiceMethod已经包含了HTTP请求和响应所需的CallAdapter和Converter等,并存到一个serviceMethodCache里面,当使用interface接口方法时,即调用动态代理类的invoke方法,将请求转为OkHttpCall。

Call.execute()

Retrofit的同步请求方法,即OkHttpCall.execute()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;

synchronized (this) {
...

call = rawCall;
if (call == null) {
try {
// 通过callFactory创建okhttp3.Call
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}

...

// okhttp3.Call使用OkHttp的execute方法,并解析响应
return parseResponse(call.execute());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();

...

ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 核心就是通过responseConverter将响应体进行转换,上面写到了Converter作用就是将ResponseBody转为T
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}

即最终通过底层的OkHttp将请求转为T类型。

Call.enqueue()

Retrofit的异步请求方法,即OkHttpCall.enqueue(),通过OkHttp的enqueue执行请求并解析响应,和上述execute基本过程是一致的,只不过是异步处理。

至此Retorfit请求发送和响应解析完毕。

OkHttp请求详见OkHttp源码分析。

0%