Retrofit 工作过程分析

126 阅读6分钟

Retrofit 工作过程分析

简介

Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的实际工作由 OkHttp 完成,而 Retrofit 负责网络请求接口的封装。当通过 Retrofit 进行网络请求时,实际上是使用 Retrofit 接口封装请求参数(如 Header、Url 等),然后由 OkHttp 完成请求操作。在服务器返回数据后,OkHttp 将原始结果交给 Retrofit,Retrofit 根据用户需求对结果进行解析。

1. Retrofit 的基本结构

理解 Retrofit 的基本结构有助于理解其工作原理:

  • Retrofit:核心类,用于配置和创建网络请求。
  • Call Adapter:将 Retrofit 的 Call 对象转换为其他类型,例如 RxJava 的 Observable
  • Converter:用于序列化和反序列化 HTTP 请求和响应的对象。
  • ServiceMethod:表示一个接口方法的详细信息,包括 HTTP 请求的方法、URL、参数等。
  • OkHttpCall:实现了 Retrofit 的 Call 接口,使用 OkHttp 发送实际的网络请求。

2. 创建 Retrofit 实例

代码示例

使用 Retrofit.Builder 创建 Retrofit 实例:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .client(new OkHttpClient())
    .build();

Retrofit.Builder 源码分析

Retrofit.Builder 是一个静态内部类,用于构建 Retrofit 实例。它允许设置基础 URL、Converter、Call Adapter 和 OkHttpClient 等。

public static final class Builder {
    private Platform platform; // 平台实例,用于获取当前平台的特定功能
    private okhttp3.Call.Factory callFactory; // OkHttp 的调用工厂,用于创建网络调用。OkHttpClient实现了Factory接口
    private HttpUrl baseUrl; // 基础 URL
    private List<Converter.Factory> converterFactories = new ArrayList<>(); // 数据转换器工厂集合
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); // 调用适配器工厂集合

    public Builder() {
        // 使用 Platform.get() 获取当前平台的实例,以便在不同平台上执行不同的逻辑
        this(Platform.get());
    }

    public Builder callFactory(okhttp3.Call.Factory factory) {
        // 设置 OkHttp 的调用工厂
        this.callFactory = checkNotNull(factory, "factory == null");
        return this;
    }

    public Builder baseUrl(HttpUrl baseUrl) {
        // 设置基础 URL
        this.baseUrl = checkNotNull(baseUrl, "baseUrl == null");
        return this;
    }

    public Builder addConverterFactory(Converter.Factory factory) {
        // 添加数据转换器工厂
        converterFactories.add(checkNotNull(factory, "factory == null"));
        return this;
    }

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
        // 添加调用适配器工厂
        adapterFactories.add(checkNotNull(factory, "factory == null"));
        return this;
    }

    public Builder callbackExecutor(Executor executor) {
        // 设置回调执行器,用于在指定的线程中执行回调
        this.callbackExecutor = checkNotNull(executor, "executor == null");
        return this;
    }
    
    public Retrofit build() {
        // 检查基础 URL 是否为空,如果为空则抛出异常
        if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
        }

        // 如果没有设置自定义的调用工厂(OkHttpClient),则使用默认的 OkHttpClient
        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
            callFactory = new OkHttpClient();
        }

        // 如果没有设置自定义的回调执行器,使用平台默认的回调执行器
        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        // 复制当前的调用适配器工厂列表,并添加平台默认的调用适配器工厂
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.adapterFactories);
        callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

        // 复制当前的转换器工厂列表
        List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

        // 创建并返回一个新的 Retrofit 实例
        return new Retrofit(callFactory, baseUrl, converterFactories, callAdapterFactories, callbackExecutor, validateEagerly);
    }
}

3. 创建接口的动态代理实现

代码示例

定义一个接口来描述 HTTP API:

public interface ApiService {
    @GET("users/{user}")
    Call<User> getUser(@Path("user") String userId);
}

通过 Retrofit 实例创建接口的实现:

ApiService apiService = retrofit.create(ApiService.class);

源码分析

在 Retrofit 中,通过 Retrofit#create 方法可以创建接口的动态代理实现,使得接口方法的调用能够被拦截并进入指定的处理逻辑。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
            // 创建 ServiceMethod 对象,通过ServiceMethod解析方法注解及方法参数
            ServiceMethod serviceMethod = loadServiceMethod(method);

            // 创建 OkHttpCall 实例来处理 HTTP 请求
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

            // 接收一个 `okHttpCall` 对象作为参数,并返回 Call 对象
            return serviceMethod.callAdapter.adapt(okHttpCall);
        }
    });
}
  • Proxy.newProxyInstance() 方法: 创建动态代理对象,需要指定类加载器、实现的接口数组和 InvocationHandler 对象,用于处理方法调用。
  • InvocationHandler.invoke() 方法: 当代理实例上的方法被调用时执行,负责拦截方法调用并进行相应处理。

4. 创建 Call 对象

代码示例

Call<User> call = apiService.getUser("exampleUser");

源码分析

当调用 apiService.getUser 方法后,会执行动态代理类中的 invoke 方法。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
            // 创建 ServiceMethod 对象,通过ServiceMethod解析方法注解及方法参数
            ServiceMethod serviceMethod = loadServiceMethod(method);

            // 创建 OkHttpCall 实例来处理 HTTP 请求
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

            // 接收一个 `okHttpCall` 对象作为参数,并返回 Call 对象
            return serviceMethod.callAdapter.adapt(okHttpCall);
        }
    });
}
  • ServiceMethod 对象创建: 通过 loadServiceMethod() 方法解析方法的注解,创建包含 HTTP 请求详细信息的 ServiceMethod 对象。
  • OkHttpCall 对象创建: 使用 ServiceMethod 对象和方法参数创建 OkHttpCall 实例,用于执行 HTTP 请求。
  • CallAdapter 对象创建:ServiceMethodbuild 方法中创建 CallAdapter 对象,用于将 OkHttpCall 适配为接口方法的返回类型。
  • callAdapter.adapt(okHttpCall): 它接收一个 okHttpCall 对象作为参数,并返回 Call 对象。代码示例中的 Call<User> call 就是通过 callAdapter.adapt(okHttpCall) 方法返回的。

如果不设置自定义的 CallAdapterFactory,Retrofit 默认使用 ExecutorCallAdapterFactoryExecutorCallAdapterFactory 源码如下:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    final Executor callbackExecutor;

    ExecutorCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
    }

    @Override
    public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }

            @Override
            public <R> Call<R> adapt(Call<R> call) {
                return new ExecutorCallbackCall<>(callbackExecutor, call);
            }
        };
    }
}

从上面代码可以看到,callAdapter.adapt(okHttpCall) 方法返回的是 ExecutorCallbackCall 对象。

5. 发起请求

代码示例

调用接口方法发起网络请求:

// Call<User> call = apiService.getUser("exampleUser");
call.enqueue(new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        // Handle response
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // Handle failure
    }
});

源码分析

在分析 Call 对象创建过程时,可以发现 callAdapter.adapt(okHttpCall) 方法返回的是 ExecutorCallbackCall 对象,因此 call.enqueue(new Callback<User>() {}) 方法最终调用的也是 ExecutorCallbackCall 对象的 enqueue 方法。

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
        this.callbackExecutor = callbackExecutor;
        this.delegate = delegate;
    }

    @Override
    public void enqueue(final Callback<T> callback) {
        if (callback == null) throw new NullPointerException("callback == null");

        delegate.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
                // ...
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
                // ...
            }
        });
    }
}

ExecutorCallbackCallenqueue 方法中,调用了 delegate.enqueue(new Callback<T>() {}),其中 delegate 就是传递进来的 OkHttpCall 对象。 OkHttpCall 类实现了 Call 接口,使用 OkHttp 发送实际的网络请求:

final class OkHttpCall<T> implements Call<T> {
    private final ServiceMethod<T> serviceMethod;
    private final Object[] args;

    OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
    }

    @Override
    public void enqueue(Callback<T> callback) {
        // 使用 OkHttp 发送异步请求
    }
}

总结

Retrofit 的工作过程可以概括为以下几个步骤:

  1. 创建 Retrofit 实例: 使用 Retrofit.Builder 配置基础 URL、Converter、Call Adapter 和 OkHttpClient 等。
  2. 定义接口并创建动态代理实现: 定义描述 HTTP API 的接口,并通过 Retrofit#create 方法创建接口的动态代理实现。
  3. 创建 Call 对象: 调用接口方法时,通过动态代理创建 ServiceMethodOkHttpCall 对象,并使用 CallAdapterOkHttpCall 适配为接口方法的返回类型。
  4. 发起请求: 调用 Call 对象的 enqueue 方法,实际由 OkHttpCall 使用 OkHttp 发送异步网络请求。

通过动态代理和注解处理,Retrofit 极大地简化了网络请求的编写和维护。