Retrofit 源码解析

源码基于 com.squareup.retrofit2:retrofit:2.9.0。

概述

  • Builder 模式构建;
  • 动态代理;
  • 自定义注解;
  • 默认只能将响应体转换为 OkHttp 中的 ResponseBody。

Retrofit 只负责生产能做网络请求的工作对象,他有点像一个工厂,只提供产品,工厂本身不处理网络请求,产品才能处理网络请求。

Retrofit

基本使用

public interface GitHubService {
    @GET("/users/{user}")
    Call<GitHubUser> getUser(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();

GitHubService service = retrofit.create(GitHubService.class);
Call<GitHubUser> userCall = service.getUser("square");
userCall.enqueue(new Callback<GitHubUser>() {
    @Override
    public void onResponse(Call<GitHubUser> call, Response<GitHubUser> response) {
        GitHubUser user = response.body();
    }

    @Override
    public void onFailure(Call<GitHubUser> call, Throwable t) {
    }
});

源码分析

Retrofit 整体流程如下:

Retrofit 流程

1. 构造 Retrofit 对象

// Retrofit.java
public static final class Builder {
    Builder(Platform platform) {
        this.platform = platform;
    }

    public Builder() {
        this(Platform.get());
    }

    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) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        // Make a defensive copy of the adapters and add the default Call adapter.
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        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.
        converterFactories.add(new BuiltInConverters());
        converterFactories.addAll(this.converterFactories);
        converterFactories.addAll(platform.defaultConverterFactories());

        return new Retrofit(
            callFactory,
            baseUrl,
            unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories),
            callbackExecutor,
            validateEagerly);
    }
}
  1. url 不能为空;
  2. callFactory 默认为 OkHttpClient;
  3. 支持 Java 和 Android 平台。
// Platform.java
private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android()
        : new Platform(true);
}

2. 创建服务接口对象

// Retrofit.java
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);
              }
            });
}

private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        // ...
        throw new IllegalArgumentException(message.toString());
      }
      // 检查父接口
      Collections.addAll(check, candidate.getInterfaces());
    }

    //是否提前加载服务方法
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
}
  1. 服务类必须是接口,且不支持泛型;
  2. 判断是否预加载服务方法;
  3. 通过动态代理实例化服务接口对象。

3. 解析服务方法上的注解

// Retrofit.java
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);
                }
            });
}

ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = ServiceMethod.parseAnnotations(this, method);
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}

通过动态对象调用服务方法。

  1. 服务方法存在,直接返回;
  2. 服务方法不存在,解析服务方法,并添加到缓存。
// ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
        throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
  1. 根据注解解析出请求方法,相对地址和请求头等数据,并包装成 RequestFactory;
  2. 服务方法返回类型不能是 void,类型变量和通配符类型;
  3. 返回 ServiceMethod 实例。
// RequestFactory.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
}

RequestFactory build() {
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }

    // 参数检查
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
    }

    // 必要的数据合法性检查
    return new RequestFactory(this);
}

private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
    } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
    } else if (annotation instanceof retrofit2.http.Headers) {
        headers = parseHeaders(headersToParse);
    } else if (annotation instanceof Multipart) {
        isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
        isFormEncoded = true;
    }
}

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
    this.httpMethod = httpMethod;
    this.hasBody = hasBody;

    if (value.isEmpty()) {
        return;
    }

    // Get the relative URL path and existing query string, if present.
    int question = value.indexOf('?');
    if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
            throw methodError(
                method,
                "URL query string \"%s\" must not have replace block. "
                    + "For dynamic query parameters use @Query.",
                queryParams);
        }
    }

    this.relativeUrl = value;
    this.relativeUrlParamNames = parsePathParameters(value);
}
  1. 根据具体的注解类型解析出数据;
// HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // ...
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
        // Kotlin 协程方法
    } else {
        // Call<GitHubUser>,Observable<GitHubUser>
        adapterType = method.getGenericReturnType();
    }
    // 查找能处理此请求的 CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    // Call<GitHubUser> 中的 GitHubUser
    Type responseType = callAdapter.responseType();
    // 查找能处理此请求的响应转换器
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      // ...
    } else {
      // ...
    }
}
  1. 适配 CallAdapter;
  2. 查找能处理此返回类型的 ConverterFactory。默认的 BuiltInConverters 只能处理 ResponseBody 和 Void 类型;
  3. 返回 CallAdapted 对象。

通过服务方法发起网络请求

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

    @Override
    final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }

    protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

    static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
        private final CallAdapter<ResponseT, ReturnT> callAdapter;

        @Override
        protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
            // DefaultCallAdapterFactory$CallAdapter
            return callAdapter.adapt(call);
        }
    }
}

final class DefaultCallAdapterFactory extends CallAdapter.Factory {

    @Override
    public @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        if (!(returnType instanceof ParameterizedType)) {
            throw new IllegalArgumentException(
                "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
        }
        final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

        final Executor executor =
            Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
                ? null
                : callbackExecutor;

        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);
            }
        };
    }

    static final class ExecutorCallbackCall<T> implements Call<T> {

        @Override
        public void enqueue(final Callback<T> callback) {
            // delegate 是 retrofit2.OkHttpCall
            delegate.enqueue(
                new Callback<T>() {
                    @Override
                    public void onResponse(Call<T> call, final Response<T> response) {
                    callbackExecutor.execute(
                        () -> {
                            if (delegate.isCanceled()) {
                                // Emulate OkHttp's behavior of throwing/delivering an IOException on
                                // cancellation.
                                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                            } else {
                                callback.onResponse(ExecutorCallbackCall.this, response);
                            }
                        });
                    }

                    @Override
                    public void onFailure(Call<T> call, final Throwable t) {
                        callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
                    }
                });
        }

        @Override
        public Response<T> execute() throws IOException {
            return delegate.execute();
        }
    }
}
  1. 适配成 retrofit2.Call<GithubUser>、Single<GitHubUser>等;
  2. 通过 retrofit2.OkHttpCall 发起 http 请求;
  3. 响应消息回调。

CallAdapter<R, T>

负责把 Retrofit 中执行网络请求的 Call 对象,转换为接口中定义的 Call 对象(eg:Observable< User >,Flowable< User >)。

public interface CallAdapter<R, T> {

    Type responseType();
    T adapt(Call<R> call);

    abstract class Factory {
        public abstract @Nullable CallAdapter<?, ?> get(
            Type returnType, Annotation[] annotations, Retrofit retrofit);

        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }

        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}

Retrofit 默认实现了两个 CallAdapter:

  1. DefaultCallAdapterFactory
  2. CompletableFutureCallAdapterFactory

Converter<F, T>

负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象。

public interface Converter<F, T> {
    T convert(F value) throws IOException;

    abstract class Factory {
        public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
            return null;
        }

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

        public @Nullable Converter<?, String> stringConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
            return null;
        }

        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }

        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}

Converter.Factory 的默认实现类有 BuiltInConvertersOptionalConverterFactory

final class BuiltInConverters extends Converter.Factory {
    @Override
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
        if (type == ResponseBody.class) {
            return Utils.isAnnotationPresent(annotations, Streaming.class)
                ? StreamingResponseBodyConverter.INSTANCE
                : BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        if (checkForKotlinUnit) {
            try {
                if (type == Unit.class) {
                return UnitResponseBodyConverter.INSTANCE;
                }
            } catch (NoClassDefFoundError ignored) {
                checkForKotlinUnit = false;
            }
        }
        return null;
    }
}

ParameterHandler<T>

负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数。

OkHttpCall<T>

final class OkHttpCall<T> implements Call<T> {

    @Override
    public void enqueue(final Callback<T> callback) {

        synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;

            call = rawCall;
            failure = creationFailure;
            if (call == null && failure == null) {
                call = rawCall = createRawCall();
            }
        }

        call.enqueue(
            new okhttp3.Callback() {
                @Override
                public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                    Response<T> response = parseResponse(rawResponse);
                    callback.onResponse(OkHttpCall.this, response);
                }
            });
    }

    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();

        // Remove the body's source (the only stateful object) so we can pass the response along.
        rawResponse =
            rawResponse
                .newBuilder()
                .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
                .build();

        ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
        T body = responseConverter.convert(catchingBody);
        return Response.success(body, rawResponse);
    }
}

总结

  1. 构造 retrofit,核心参数有 baseurl,callFactory(默认 okhttpclient),converterFactories,adapterFactories 和 excallbackExecutor。
  2. 通过 Retrofit#create() 方法获取接口的实现类,运用了 Java 的动态代技术。
  3. 调用服务方法时会先实例化 ServiceMethod。ServiceMethod 通过解析服务方法上的注解
    在 invoke 方法内部,拿到我们所声明的注解以及实参等,构造 ServiceMethod。ServiceMethod 中解析了大量的信息,最后可以通过 toRequest 构造出 okhttp3.Request 对象。有了 okhttp3.Request 对象就可以很自然的构建出 okhttp3.call,最后 calladapter 对 Call 进行装饰返回。
    拿到 Call 就可以执行 enqueue 或者 execute 方法了

responseBodyConverter 主要是对应@Body 注解,完成 ResponseBody 到实际的返回类型的转化,这个类型对应 Call< XXX >里面的泛型,其实@Part 等注解也会需要 responseBodyConverter,只不过我们的参数类型都是 RequestBody,由默认的 converter 处理了。
requestBodyConverter 完成对象到 RequestBody 的构造。
一定要注意,检查 type 如果不是自己能处理的类型,记得 return null (因为可以添加多个,你不能处理 return null ,还会去遍历后面的 converter).

参考

[1] 从架构角度看 Retrofit 的作用、原理和启示
[2] 拆轮子系列:拆 Retrofit

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容