美文网首页
Retrofit源码解读

Retrofit源码解读

作者: 几行代码 | 来源:发表于2019-02-11 21:51 被阅读0次

先来梳理一下Retrofit网络通信的过程,这里总结了一下:
网络通信过程:
1.创建Retrofit实例
2.定义一个网络请求接口并为接口中的方法添加注解
3.通过动态代理生成网络请求对象(也就是解析网络请求接口中的注解,解析完成后来配置网络请求参数)
4.通过网络请求适配器将网络请求对象进行平台适配
5.通过网络请求执行器(call Retrofit中的call和Okhttp中的call是一样的)发送网络请求
6.通过数据转换器解析数据
7.通过回调执行器切换线程
8.用户在主线程处理返回结果

从源码详细看看:
创建Retrofit实例

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

先看一下内部类Builder:

/**
     * 内部类 Builder
     */
    public static final class Builder {
        private final Platform platform;  // 平台  android  java8,默认用的都是android平台
        private @Nullable
        okhttp3.Call.Factory callFactory;  // 请求网络的工厂,默认是okHttp的
        private HttpUrl baseUrl; // 网络请求的基地址,传进来的是String,这里要把String转换成HttpUrl
        private final List<Converter.Factory> converterFactories = new ArrayList<>(); // 数据转换器工厂
        private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); // 网络请求适配器工厂
        private @Nullable
        Executor callbackExecutor; // 执行异步回调
        private boolean validateEagerly; // 标志,是否立即解析接口中的方法,动态代理解析接口中的方法的时候用到的

        Builder(Platform platform) {
            this.platform = platform;
        }

        public Builder() {
            this(Platform.get());  // 默认安卓平台,里面有默认网络请求适配器call方法
        }

        Builder(Retrofit retrofit) {
            platform = Platform.get();
            callFactory = retrofit.callFactory;
            baseUrl = retrofit.baseUrl;

            converterFactories.addAll(retrofit.converterFactories); // 添加设置的数据转换器
            // Remove the default BuiltInConverters instance added by build().
            converterFactories.remove(0); // 移除默认的数据转换器

            callAdapterFactories.addAll(retrofit.callAdapterFactories); // 添加适配器工厂
            // Remove the default, platform-aware call adapter added by build().
            callAdapterFactories.remove(callAdapterFactories.size() - 1); // 移除默认的适配器

            callbackExecutor = retrofit.callbackExecutor;
            validateEagerly = retrofit.validateEagerly;
        }

        /**
         * 定制客户端的请求,可定制OkHttpClient 比如添加相应的拦截器等
         */
        public Builder client(OkHttpClient client) {
            return callFactory(checkNotNull(client, "client == null"));
        }

        /**
         * 自定义网络请求执行工厂,默认的是 okHttp
         */
        public Builder callFactory(okhttp3.Call.Factory factory) {
            this.callFactory = checkNotNull(factory, "factory == null");
            return this;
        }

        /**
         * 设置http的主机名(域名) + 端口号 *以/结尾
         */
        public Builder baseUrl(String baseUrl) {
            checkNotNull(baseUrl, "baseUrl == null"); // 先判断 baseUrl是否为空
            HttpUrl httpUrl = HttpUrl.parse(baseUrl); // 把baseUrl转换成HttpUrl
            if (httpUrl == null) {
                throw new IllegalArgumentException("Illegal URL: " + baseUrl);
            }
            return baseUrl(httpUrl);
        }

        /**
         * 承接上面的方法,解析处理 baseUrl
         */
        public Builder baseUrl(HttpUrl baseUrl) {
            checkNotNull(baseUrl, "baseUrl == null");
            List<String> pathSegments = baseUrl.pathSegments(); // 拆成集合碎片
            if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
                throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); // baseUrl必须用“/”结尾
            }
            this.baseUrl = baseUrl; // 赋值给内部类的成员变量
            return this;
        }

        /**
         * 为对象的序列化和反序列化添加数据转换器工厂.
         */
        public Builder addConverterFactory(Converter.Factory factory) {
            converterFactories.add(checkNotNull(factory, "factory == null"));
            return this;
        }

        /**
         * 添加调用适配器工厂 RxJava 的观察者 observe 默认是okHttp的call
         */
        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
            callAdapterFactories.add(checkNotNull(factory, "factory == null"));
            return this;
        }

        /**
         * 执行异步回调
         */
        public Builder callbackExecutor(Executor executor) {
            this.callbackExecutor = checkNotNull(executor, "executor == null");
            return this;
        }

        /**
         * 返回可修改的调用适配器工厂列表.
         */
        public List<CallAdapter.Factory> callAdapterFactories() {
            return this.callAdapterFactories;
        }

        /**
         * 返回可修改的(数据)转换器工厂列表.
         */
        public List<Converter.Factory> converterFactories() {
            return this.converterFactories;
        }

        /**
         * 设置标志,是否立即解析接口中的方法,动态代理解析接口中的方法的时候用到的
         */
        public Builder validateEagerly(boolean validateEagerly) {
            this.validateEagerly = validateEagerly;
            return this;
        }

        /**
         * 根据上面所配置的值创建实例,如果没有自定义配置网络请求,默认创建并使用okHttp请求
         */
        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();
            }

            // 创建并复制网络请求适配器工厂,并添加默认的网络请求适配器
            List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
            callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

            // 创建并复制数据解析器工厂
            List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size());

            // 首先添加内置转换器工厂。这可以防止覆盖它,确保在使用时是正确的
            converterFactories.add(new BuiltInConverters()); // 添加默认的数据转换器工厂
            converterFactories.addAll(this.converterFactories); // 添加用户自定义设置进来的数据转换工厂

            // https://blog.csdn.net/cilen/article/details/7744969 题外说一下unmodifiableList用法
            return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
                    unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
        }
    }

内部类中包含了七个成员变量和三个构造函数:

  • 七个成员变量:
private final Platform platform;  // 平台  android  java8,默认用的都是android平台
private okhttp3.Call.Factory callFactory;  // 请求网络的工厂,默认是okHttp的
private HttpUrl baseUrl; // 网络请求的基地址,传进来的是String,这里要把String转换成HttpUrl
private final List<Converter.Factory> converterFactories = new ArrayList<>(); // 数据转换器工厂
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); // 网络请求适配器工厂
private Executor callbackExecutor; // 执行异步回调
private boolean validateEagerly; // 标志,是否立即解析接口中的方法,动态代理解析接口中的方法的时候用到的
  • 三个构造函数:

一个是直接传入Retrofit,其他两个是传入平台和空构造函数,不传默认是Android平台。

  • 在这个内部类中可以看到很灵活的提供了很多方法:

包括自定义OkHttpClient、网络请求执行工厂(默认是okhttp3)、设置设置http的主机名(域名) + 端口号 *以/结尾、添加数据解析的工厂(例:我们经常使用的GsonConverterFactory.create())、调用工厂的适配器(例:RxJavaCallAdapterFactory.create())...等等。

  • 这里需要注意一下:
/**
         * 设置http的主机名(域名) + 端口号 *以/结尾
         */
        public Builder baseUrl(String baseUrl) {
            checkNotNull(baseUrl, "baseUrl == null"); // 先判断 baseUrl是否为空
            HttpUrl httpUrl = HttpUrl.parse(baseUrl); // 把baseUrl转换成HttpUrl
            if (httpUrl == null) {
                throw new IllegalArgumentException("Illegal URL: " + baseUrl);
            }
            return baseUrl(httpUrl);
        }

        /**
         * 承接上面的方法,解析处理 baseUrl
         */
        public Builder baseUrl(HttpUrl baseUrl) {
            checkNotNull(baseUrl, "baseUrl == null");
            List<String> pathSegments = baseUrl.pathSegments(); // 拆成集合碎片
            if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
                throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); // baseUrl必须用“/”结尾
            }
            this.baseUrl = baseUrl; // 赋值给内部类的成员变量
            return this;
        }

传入的baseUrl必须用“/”结尾,否则会抛出异常。

  • 这里涉及到一个类Platform:
class Platform {
    private static final Platform PLATFORM = findPlatform();

    static Platform get() {
        return PLATFORM;
    }

    private static Platform findPlatform() {
        try {
            Class.forName("android.os.Build");
            if (Build.VERSION.SDK_INT != 0) {
                return new Android();  // 安卓平台
            }
        } catch (ClassNotFoundException ignored) {
        }
        try {
            Class.forName("java.util.Optional");
            return new Java8();  // Java8平台
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
    }

    @Nullable Executor defaultCallbackExecutor() {
        return null;
    }

    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
            return new ExecutorCallAdapterFactory(callbackExecutor); // 创建默认的CallAdapterFactory  ---> ExecutorCallAdapterFactory
        }
        return DefaultCallAdapterFactory.INSTANCE;
    }

    boolean isDefaultMethod(Method method) {
        return false;
    }

    @Nullable Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, @Nullable Object... args) throws Throwable {
        throw new UnsupportedOperationException();
    }

    /**
     *  Java 8 平台
     */
    @IgnoreJRERequirement // Only classloaded and used on Java 8.
    static class Java8 extends Platform {
        @Override boolean isDefaultMethod(Method method) {
            return method.isDefault();
        }

        @Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
                                             @Nullable Object... args) throws Throwable {
            // Because the service interface might not be public, we need to use a MethodHandle lookup
            // that ignores the visibility of the declaringClass.
            Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
            constructor.setAccessible(true);
            return constructor.newInstance(declaringClass, -1 /* trusted */)
                    .unreflectSpecial(method, declaringClass)
                    .bindTo(object)
                    .invokeWithArguments(args);
        }
    }

    /**
     * Android 平台
     */
    static class Android extends Platform {
        @Override public Executor defaultCallbackExecutor() {
            // 持有有个主线程的Handler,发送响应是事件到主线程
            return new MainThreadExecutor(); // 构建一个用来将响应事件发送到Main线程
        }

        @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
            if (callbackExecutor == null) throw new AssertionError();
            // 返回一个默认的Call(执行器)的适配器工厂,就是用来将执行结果转换成你想要的返回对象,比如,你想要Observer<Object> 等
            return new ExecutorCallAdapterFactory(callbackExecutor);
        }

        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());  // 创建主线程的handler

            @Override public void execute(Runnable r) {
                handler.post(r);
            }
        }
    }
}

可以看到选择Android平台(默认),会默认创造一个MainThreadExecutor主线程执行者,意味着Retrofit的网络请求最终回调到主线程中。

下面接着看看Retrofit中的成员变量:

/**
     * Method是http的请求方法,ServiceMethod 代表网络请求接口中,对方法注解后,我们要通过解析,解析
     * 之后的对象就是这里的ServiceMethod,和注解中的请求方法成对出现的,一一对应的
     * serviceMethodCache用于缓存,请求方法、配置、转换器、适配器等等
     */
    private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

    final okhttp3.Call.Factory callFactory;  // 请求网络okhttp的工厂
    final HttpUrl baseUrl;   // 网络请求url的基地址
    final List<Converter.Factory> converterFactories; // 数据转换器工厂集合,就是把服务端返回的json转换成我们对应的JavaBean,这是个放置数据转换器的工厂
    final List<CallAdapter.Factory> callAdapterFactories; // 网络请求适配器工厂集合 ,就是把call对象转换成其他类型,比如转换成RxJava的被观擦者
    final @Nullable Executor callbackExecutor; // 用于执行回调的
    final boolean validateEagerly; // 表示标志位的,表示我们是否立即解析接口中的方法,动态代理解析接口中的方法的时候用到的

这里重点说一下serviceMethodCache这个Map集合,它是一个ConcurrentHashMap说明是线程安全的。它的key是Method,即网络请求接口定义的带注解的方法(非默认),Value是一个ServiceMethod,ServiceMethod其实就是把网络请求接口中带注解的方法解析之后的对象。
它们是一一对应的,网络请求接口一个带注解的方法(非默认),对应一个ServiceMethod。

最后就是Retrofit的重要内容是怎么把网络接口的注解翻译成一个个http请求:

ServiceApi service = retrofit.create(ServiceApi.class);
Call<String> call = service.tag("android");
  • create方法的源码:
/**
     * @param service 构建API的生产接口
     * @return 返回 构建API的生产接口
     */
    @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
    public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service); // 验证该接口的合法性
        if (validateEagerly) {
            eagerlyValidateMethods(service); // 立即(验证))解析接口中的方法
        }
        // 通过动态代理将构建API的生产接口的注解翻译成一个个http请求,再由线程池来执行这一个个的网络请求
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
                new InvocationHandler() {
                    private final Platform platform = Platform.get();

                    @Override
                    public 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); // 如果该方法来自对象,由该实例正常调用
                        }
                        if (platform.isDefaultMethod(method)) { //如果该方法是声明为default,则正常调用该方法
                            return platform.invokeDefaultMethod(method, service, proxy, args);
                        }
                        // 从缓存ServiceMethod的方法的集合中根据Method获取该ServiceMethod实例对象
                        ServiceMethod<Object, Object> serviceMethod =
                                (ServiceMethod<Object, Object>) loadServiceMethod(method);
                        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // 创建一个请求执行对象,就是okHttp中的Call
                        return serviceMethod.adapt(okHttpCall);  // 网络请求适配器的使用以及异步执行器的回调
                    }
                });
    }

    /**
     * 会在Retrofit第一次cretae的时候调用
     *
     * 立即(验证))解析接口中的方法
     * @param service  构建API的生产接口
     */
    private void eagerlyValidateMethods(Class<?> service) {
        Platform platform = Platform.get();
        for (Method method : service.getDeclaredMethods()) { // 利用反射获取生产接口中的所有方法(私有,默认、公有))
            if (!platform.isDefaultMethod(method)) { //判断是不是default方法,jdk7以后接口中可以编写方法的实现,但是必须在方法前面设置一个关键字default
                loadServiceMethod(method);
            }
        }
    }

    /**
     * 加载接口中的非default方法,构建一个ServiceMethod对象,以Method为Key,该对象作为value添加到serviceMethodCache集合缓存起来
     */
    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;

        synchronized (serviceMethodCache) {
            result = serviceMethodCache.get(method);
            if (result == null) {
                // 传入Retrofit实例和Method到MethodBuild对象构建一个ServiceMethod,该对象将会包含Retrofit所有数据,以后就是用做对象完成数据请求以及封装
                result = new ServiceMethod.Builder<>(this, method).build();
                serviceMethodCache.put(method, result);
            }
        }
        return result;
    }

核心就是通过动态代理和反射实现的,上面代码中注释很详尽,这里就不展开细说了。
动态代理的讲解:https://www.jianshu.com/p/2c1173635bc2
PS:这里有一个注意点:

  • jdk7以后接口中可以编写方法的实现,但是必须在方法前面设置一个关键字`default'
    示例如下:
public interface Test {

    // TODO jdk7以后接口中可以编写方法的实现,但是必须在方法前面设置一个关键字`default'
    default String setName() {
        return "测试";
    }

}

接下来就是发起具体的网络请求了,其实就是操作的OkHttp3:

//发送网络请求(异步)
        call.enqueue(new Callback<String>() {
            //请求成功时回调
            @Override
            public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                //请求处理,输出结果
                assert response.body() != null;
                response.body().toString();
                System.out.println("*******" + Thread.currentThread().getName() + "&&&&&&&&");
            }

            //请求失败时候的回调
            @Override
            public void onFailure(@NonNull Call<String> call, @NonNull Throwable throwable) {
                System.out.println("连接失败");
                System.out.println("*******" + Thread.currentThread().getName() + "&&&&&&&&");
            }
        });

这里用到了网络请求的适配器,在上面我们将默认平台Android的时候。。系统会默认创建一个网络请求适配器ExecutorCallAdapterFactory:

  • 我们来看看源码
package retrofit2;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.concurrent.Executor;
import okhttp3.Request;

import static retrofit2.Utils.checkNotNull;

/**
 * 默认创建的 CallAdapterFactory,当然也可以自定义RxJava的Observer<Object>,这里只说默认的
 */
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    final Executor callbackExecutor;

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

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

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

    static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor; // 回调的Executor (其实就是Android那个Platform中的MainThreadExecutor)
        final Call<T> delegate;   // 代理Call 真正的执行Call

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

        // 发送异步请求
        @Override public void enqueue(final Callback<T> callback) {
            checkNotNull(callback, "callback == null");

            delegate.enqueue(new Callback<T>() {
                @Override public void onResponse(Call<T> call, final Response<T> response) {
                    // 发送响应到主线程
                    callbackExecutor.execute(new Runnable() {
                        @Override public void run() {
                            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(new Runnable() {
                        @Override public void run() {
                            callback.onFailure(ExecutorCallbackCall.this, t);
                        }
                    });
                }
            });
        }

        // 判断该Call是否已经执行
        @Override public boolean isExecuted() {
            return delegate.isExecuted();
        }

        // 发送同步请求
        @Override public Response<T> execute() throws IOException {
            return delegate.execute();
        }

        // 取消该call 就是在okHttp的call池中移除
        @Override public void cancel() {
            delegate.cancel();
        }

        // 判断该Call是否已经取消掉了
        @Override public boolean isCanceled() {
            return delegate.isCanceled();
        }

        @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
        @Override public Call<T> clone() {
            return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
        }

        @Override public Request request() {
            return delegate.request();
        }
    }
}

打断点,最终走的还是OkHttp的方法:


OkHttpCall

Retrofit的使用:https://www.jianshu.com/p/dac9a1c02525

相关文章

网友评论

      本文标题:Retrofit源码解读

      本文链接:https://www.haomeiwen.com/subject/qbeceqtx.html