Obelieve's Blog  >  All tags  >  Okhttp

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.接口请求测试部分
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.🔗

//先进入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)🔗

 //从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)方法🔗

/**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.🔗

//从上一步最后返回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】用法示例源码

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>
}
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();
        }
    }
}
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();
    }
}
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;
    }
}
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;
    }
}
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 + '\'' +
                    '}';
        }
    }
}