Retrofit源码分析 2.10.0-SNAPSHOT

流程图.png

1. 介绍

Retrofit主要是基于OKHttp进一步封装的网络请求的框架。它采用了一种接口方法声明请求的方式,使用方法注解和方法参数注解进行标记请求信息,通过动态代理访问接口方法并解析Method,最后将请求信息汇总组装成okhttp3.Request对象,再根据接口方法返回值类型决定调用适配器(CallAdapter),内部通过okhttp3.Call.enqueue(..) 或okhttp3.Call.execute() 同步/异步请求,请求响应后通过转换器(Converter)把okhttp3.ResponseBody数据再进行一次转换得到最后的数据。

2.suspend 关键字,Kotlin 协程方式使用

接口方法标记为suspend,会把返回类型T 包装成Call,然后使用异步(enqueue),通过KotlinExtensions.kt下的Call.await()包装成协程执行(请求时挂起协程,响应后协程resume继续执行)。

3.CallAdapter实现类介绍

  • RxJava2CallAdapterFactory.create(isAsync);//isAsync = true or false来判断是否是异步或同步请求。默认是同步请求也就是false。
  • 默认的CallAdapter实现类
    • DefaultCallAdapterFactoryCall<T>类型的,调用同步(execute)或异步(enqueue)。
    • CompletableFutureCallAdapterFactoryCompletableFuture<T>类型的,使用异步(enqueue)。

4.用法

这一小节通过一系列不同请求方式的代码来展示相关的用法。
主要分为6个文件,具体代码文件在最后面。

  • ServiceInterface.kt 声明接口请求
  • Main.kt 测试接口请求
  • ApiConverterFactory.java 转换器工厂类
  • ApiRequestBodyConverter.java 转为RequestBody对象转换器类 (@Part 参数对象转为RequestBody)
  • ApiResponseBodyConverter.java ResponseBody对象转换器类
  • HttpBinResponse.java ResponseBody装好后的数据类

4.1 基本用法

  • 1.GET 请求下载文件
  • 2.GET 请求
  • 3.GET 请求 查询?name=value
  • 4.GET 请求 查询?name
  • 5.POST 请求
  • 6.POST 请求 表单数据提交 name=”名字”&content=”内容”
  • 7.POST 请求 多部分表单提交 multipart/form-data

4.2 进阶用法

  • 1.通过@URL 请求一个不同地址的URL
  • 2.通过Interceptor拦截器,实现动态设置不同BaseUrl

5. 源码具体示例分析

这一小节,通过一个post表单提交梳理下执行流程。以下是这个post请求的代码:分为三部分

  • 1.接口请求声明部分
  • 2.Retrofit类构建,并返回接口的实现类部分
  • 3.接口请求测试部分
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
interface ServiceInterface {
...
companion object {
var BASE_URL = "http://www.httpbin.org/"
}
@POST("/post")
@FormUrlEncoded
fun post(@Field("name") name:String,@Field("content") content:String): Call<ResponseBody>
...
}
public class Main {
...
private static ServiceInterface sServiceInterface
= new Retrofit.Builder()
.baseUrl(ServiceInterface.Companion.getBASE_URL())
.client(new OkHttpClient.Builder().build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ApiConverterFactory.create())
.build()
.create(ServiceInterface.class);
/**
* Post请求,表单提交 @FormUrlEncoded @Field
*/
@Test
public void testPostFormUrlEncoded(){
String s = null;
try {
Response<ResponseBody> response = sServiceInterface.post("名字","内容").execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}
...
}

sServiceInterface.post("名字","内容").execute();开始分析
1.先看看sServiceInterface是怎么创建的?
2.再看看调用post("名字","内容")方法是怎么回事?
3.最后看下执行execute()是怎么样的?

开始分析1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//先进入Retrofit#create(..)方法
public <T> T create(final Class<T> service) {
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
...
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args); //看重点部分
}
});
//分析1结束,通过Proxy.newProxyInstance(..)动态代理获取接口ServiceInterface代理对象。

开始分析2.

从上一步的loadServiceMethod(method).invoke(args)开始分为2个部分:

  • 2.1 loadServiceMethod(method)
  • 2.2 调用invoke(args)方法

开始分析2.1 loadServiceMethod(method)

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
 //从Retrofit#loadServiceMethod(..)开始
ServiceMethod<?> loadServiceMethod(Method method) {
...
result = ServiceMethod.parseAnnotations(this, method);
...
}
return result;
}
//ServiceMethod#parseAnnotations(..)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析生成RequestFactory对象,具体流程在【流程图】图片有描述
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

//HttpServiceMethod.parseAnnotations(..)
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
adapterType = method.getGenericReturnType();
...
//获取调用适配器CallAdapter对象,具体流程在【流程图】图片有描述
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
...
//获取转换器Converter对象,具体流程在【流程图】图片有描述
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
...
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
...
}
/**CallAdapted extends HttpServiceMethod<ResponseT, ReturnT>
HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT>
**/
//最后返回CallAdapted对象,分析2.1结束。

开始分析 2.2 调用invoke(args)方法

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
/**CallAdapted中没有invoke方法,invoke方法的实现位于它的父类HttpServiceMethod中**/
//HttpServiceMethod#invoke(..)
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
//adapt(call, args)方法的实现位于CallAdapted中
//CallAdapted#adapt(..)
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
/**调用到CallAdapter#adapt(call)方法,由于之前请求接口方法返回值是Call<ResponseBody>,所以调用DefaultCallAdapterFactory#get(..)返回callAdapter对象
**/
//DefaultCallAdapterFactory#get(..)
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
//最后返回ExecutorCallbackCall对象,分析2.2结束

开始分析3.

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
//从上一步最后返回ExecutorCallbackCall对象,开始分析
//在ExecutorCallbackCall类中
...
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//ExecutorCallbackCall#execute()
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
//由上可知delegate是OkHttpCall对象
//OkHttpCall#execute()
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
...
//获取okhttp3.Call对象,具体流程在【流程图】图片有描述
call = getRawCall();
}
...
return parseResponse(call.execute());
}
//OkHttpCall#parseResponse(call.execute())
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//Converter转换器转换数据,然后返回
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
//最后Converter转换器转换数据,然后返回retrofit2.Response对象,分析3结束。

总结

sServiceInterface.post("名字","内容").execute();

  • 1.sServiceInterface通过Proxy.newProxyInstance(..)动态代理获取接口ServiceInterface代理对象。
  • 2.调用post("名字","内容")方法时,开始执行动态代理内部方法,通过层层解析返回ExecutorCallbackCall类,其中包含OkHttpCall对象变量,OkHttpCall中主要包含了一些okhttp3.Request、okhttp3.Call.execute()等处理。
  • 3.执行execute(),最后就是执行了okhttp3.Call.execute()。

其他

  • 1.对于super和extends的上界下界:
    List<? super Food> 表示Food的超类,说明Food是?的下界 (只能add,不能get)
    List<? extends Fruit> 表示Fruit的子类,说明Fruit是?的上界 (只能get,不能add)
    class Food{}
    class Fruit extends Food {}

6. 附录

【4】用法示例源码

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
interface ServiceInterface {

companion object {
var BASE_URL = "http://www.httpbin.org/"
}

@Streaming
@GET
fun downloadFile(
@Header("RANGE") downParam: String,
@Url fileUrl: String
): Call<ResponseBody>

@GET("/")
fun get(): Call<ResponseBody>

@GET("/get")
fun get(@Query("name")name:String,@Query("content")content: String): Call<HttpBinResponse>

@GET("/get")
fun get(@QueryName name:String): Call<ResponseBody>

@POST("/post")
fun post(): Call<ResponseBody>

@POST("/post")
@FormUrlEncoded
fun post(@Field("name") name:String,@Field("content") content:String): Call<ResponseBody>

@POST("/post")
@Multipart
fun post(@Part("va") va:RequestBody,@Part("name\"; filename=\"name.png")name: File, @Part("name2\"; filename=\"name2.png")name2: File): Call<ResponseBody>
}
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class Main {

private static ServiceInterface sServiceInterface = new Retrofit.Builder().baseUrl(ServiceInterface.Companion.getBASE_URL()).client(
new OkHttpClient.Builder().addInterceptor(new Interceptor() {

private volatile String host;

public void setHost(String host) {
this.host = host;
}

@NotNull
@Override
public okhttp3.Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
HttpUrl newUrl = request.url().newBuilder().host(host).build();
request = request.newBuilder().url(newUrl).build();
}
return chain.proceed(request);
}
}).build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ApiConverterFactory.create())
.build().create(ServiceInterface.class);

{
// System.setProperty("http.proxyHost", "127.0.0.1");
// System.setProperty("https.proxyHost", "127.0.0.1");
// System.setProperty("http.proxyPort", "8888");
// System.setProperty("https.proxyPort", "8888");
}

public static void main(String[] args) throws Exception {
}

/**
* Get请求,
*/
@Test
public void testGet(){
String s = null;
try {
Response<ResponseBody> response = sServiceInterface.get().execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}

/**
* Get请求下载,带有 @Streaming
*/
@Test
public void testGetDownload(){
String url = "https://www.httpbin.org/image/png";
try {
Response<ResponseBody> response = sServiceInterface.downloadFile("Range: bytes=0-",url).execute();
BufferedSink sink = Okio.buffer(Okio.sink(new File("C:\\Users\\Administrator\\Desktop", "testImage.png")));
sink.writeAll(response.body().source());
sink.close();
System.out.println("req图片");
} catch (Exception e) {
e.printStackTrace();
}
}


/**
* Get请求,带有@QueryName ?name
*/
@Test
public void testGetQueryName(){
String s = null;
try {
Response<ResponseBody> response = sServiceInterface.get("name").execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}

/**
* Get请求,带有@Query ?name=value&name2=value2
*/
@Test
public void testGetQuery(){
String s = null;
try {
Response<HttpBinResponse> response = sServiceInterface.get("名字","内容").execute();
s = response.body().getData();
System.out.println("url="+new Gson().fromJson(s,HttpBinResponse.Entity.class).getUrl()+" \n"+s);
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* Post请求
*/
@Test
public void testPost(){
String s = null;
try {
Response<ResponseBody> response = sServiceInterface.post().execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}

/**
* Post请求,表单提交 @FormUrlEncoded @Field
*/
@Test
public void testPostFormUrlEncoded(){
String s = null;
try {
Response<ResponseBody> response = sServiceInterface.post("名字","内容").execute();
s = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}

/**
* Post请求,多部分表单提交 @Multipart @Part
*/
@Test
public void testPostMultipart() {
RequestBody aa = RequestBody.create("name=11&value=22", MediaType.parse("text/plain"));
try {
Response<ResponseBody> response = sServiceInterface.post(aa,new File("C:\\Users\\Administrator\\Desktop\\1.png"),new File("C:\\Users\\Administrator\\Desktop\\2.png")).execute();
String s = response.body().string();
System.out.println(s);
HttpBinResponse.Entity entity = new Gson().fromJson(s, HttpBinResponse.Entity.class);
String name = entity.getFile().get("name").replace("data:image/png;base64,","");
File file = new File("C:\\Users\\Administrator\\Desktop\\multipart.png");
FileOutputStream out = new FileOutputStream(file);
out.write(Base64.getDecoder().decode(name));
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ApiConverterFactory extends Converter.Factory{

public static ApiConverterFactory create(){
return new ApiConverterFactory();
}

@Nullable
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new ApiRequestBodyConverter();
}

@Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new ApiResponseBodyConverter();
}
}
1
2
3
4
5
6
7
8
9
10
11
public class ApiRequestBodyConverter implements Converter<File, RequestBody> {
@Nullable
@Override
public RequestBody convert(File value) throws IOException {
if(value.getAbsolutePath().contains(".png")){
RequestBody bodyParams = RequestBody.create(value,MediaType.parse("image/png"));
return bodyParams;
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ApiResponseBodyConverter implements Converter<ResponseBody, HttpBinResponse> {

@Nullable
@Override
public HttpBinResponse convert(ResponseBody value) throws IOException {
String json = value.string();
HttpBinResponse response = new HttpBinResponse();
try{
response.setCode(1);
response.setMessage("Success");
response.setData(json);
}catch (Exception e){
e.printStackTrace();
}
return response;
}
}
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
public class HttpBinResponse {

private String message;
private int code;
private Entity entity;
private String data;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public Entity getEntity() {
return entity;
}

public void setEntity(Entity entity) {
this.entity = entity;
}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

public static class Entity{
private Object args;
private String data;
private Map<String,String> files;
private Map<String,String> form;
private Map<String,String> headers;
private String json;
private String origin;
private String url;

public Object getArg() {
return args;
}

public void setArg(Object arg) {
args = arg;
}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

public Map<String,String> getFile() {
return files;
}

public void setFile(Map<String,String> file) {
files = file;
}

public Map<String, String> getForm() {
return form;
}

public void setForm(Map<String, String> form) {
this.form = form;
}

public Map<String, String> getHeader() {
return headers;
}

public void setHeader(Map<String, String> header) {
headers = header;
}

public String getJson() {
return json;
}

public void setJson(String json) {
this.json = json;
}

public String getOrigin() {
return origin;
}

public void setOrigin(String origin) {
this.origin = origin;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

@Override
public String toString() {
return "Data{" +
"args=" + args +
", data='" + data + '\'' +
", files=" + files +
", form=" + form +
", headers=" + headers +
", json='" + json + '\'' +
", origin='" + origin + '\'' +
", url='" + url + '\'' +
'}';
}
}
}