源码笔记之Retrofit

有一段时间没分享源码的东西了,最近两天有时间,顺便看下Retrofit源码,一是为了完善原来的理解,二是跟大家分享有理解偏差的地方希望大家批评。Retrofit火了很长时间了,刚开始问世时就在自己的网络请求模块引入使用,一晃好几年了,哈哈。

我们直接从我们平时的项目配置开始


        val client = okHttpClient
                .addInterceptor(interceptor)
                .cache(Cache(File(App.instance.getCacheDir(), "cache"), 1024 * 1024 * 10)) // 缓存设置
                .addNetworkInterceptor(mRewriteCacheControlInterceptor) // 网络设置
                .retryOnConnectionFailure(true) // 连接失败时尝试重连
                .build()
        val builder = Retrofit.Builder() // 使用变种Buidler模式构建对象
                .baseUrl(HttpMethod.ROOT_API_URL) // 基础url
                .client(client) 
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 利用工厂模式添加CallAdapter
        return builder
                .addConverterFactory(GsonConverterFactory.create()) // 利用工厂模式添加解析方式
                .build()

 

Retrofit的精巧之处就在于它使用了大量的设计模式来进行解耦,刚开始使用时可能感觉还很不适应,但后续在了解了它或添加其他细化功能时你就感觉了它的强大。

首先构建对象采用使用很广泛的Builder模式,

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

         public Retrofit build() {
            if (this.baseUrl == null) { // 必须配置baseUrl
                throw new IllegalStateException("Base URL required.");
            } else {
                Factory callFactory = this.callFactory;
                if (callFactory == null) { // 默认使用OkHttp进行网络请求
                    callFactory = new OkHttpClient();
                }

                Executor callbackExecutor = this.callbackExecutor;
                if (callbackExecutor == null) { // callbackExecutor如果未设置会使用默认值赋值
                    callbackExecutor = this.platform.defaultCallbackExecutor();
                }

                List<retrofit2.CallAdapter.Factory> adapterFactories = new ArrayList(this.adapterFactories);
                adapterFactories.add(this.platform.defaultCallAdapterFactory(callbackExecutor));
                List<retrofit2.Converter.Factory> converterFactories = new ArrayList(this.converterFactories);
                return new Retrofit((Factory)callFactory, this.baseUrl, converterFactories, adapterFactories, callbackExecutor, this.validateEagerly);
            }
        }

buidler方法没什么特别的地方,只是做了一些初始化的动作,如果用户未做定制化的东西就赋予默认值。但这里需要留意一下Buidler构造里的Platform。默认情况下时使用的是其返回的值。

 static class Android extends Platform {
        Android() {
        }

        public Executor defaultCallbackExecutor() {
            return new Platform.Android.MainThreadExecutor();
        }

        Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
            if (callbackExecutor == null) {
                throw new AssertionError();
            } else {
                return new ExecutorCallAdapterFactory(callbackExecutor);
            }
        }

        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());

            MainThreadExecutor() {
            }

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

最终调用的代码即callbackExecutor的默认值为Platform下的Android类代码。

下面我们来看下一步,create方法

 public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if (this.validateEagerly) { // 手动设置了validateEagerly会触发此函数
            this.eagerlyValidateMethods(service);
        }
        // 使用动态代理模式以及后续处理一系列解析及配置网络请求操作,很亮眼的一处
        // service.getClassLoader()指定代理的classloader与目标对象一致
        // new Class[]{service}指定数组接口,代理对象默认实现该接口,以便恰当的时候调用目标对象的方法
        // 匿名内部类 InvocationHandler是为了调用invoke是回调到当前的invoke进行解析注解等操作
        return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
            // 获取所在平台java8、android等
            private final Platform platform = Platform.get();

            public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
                // Object方法
                if (method.getDeclaringClass() == Object.class) {
                    return method.invoke(this, args);
                } else if (this.platform.isDefaultMethod(method)) {
                // java8的方法  
                    return this.platform.invokeDefaultMethod(method, service, proxy, args);
                } else {
                // android平台的关键代码在这 
                    ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
                    OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args);
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            }
        });
    }

invoke里主要做了一些平台的判断,我们直接来看android最关键的几行代码

 ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method); // 创建serviceMethod对象,这是个最关键的类,Retrofit的一系列操作都通过它,但是在新版的Retrofit中遵循单一责任原则等做了解耦抽取。
                    OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args); // 请求回调构建
                    return serviceMethod.callAdapter.adapt(okHttpCall); // 适配adapter并开始请求及后续步骤

先来看下loadServiceMethod

    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = (ServiceMethod)this.serviceMethodCache.get(method); 
        // 缓存中有直接获取
        if (result != null) {
            return result;
        } else {
            Map var3 = this.serviceMethodCache;
            synchronized(this.serviceMethodCache) {
                result = (ServiceMethod)this.serviceMethodCache.get(method);
                if (result == null) {
                    // 缓存没有时通过Builder模式创建实例
                    result = (new retrofit2.ServiceMethod.Builder(this, method)).build();
                    this.serviceMethodCache.put(method, result);// 放入缓存
                }

                return result;
            }
        }
    }

接着整,追踪到ServiceMethod

  public ServiceMethod build() {
            this.callAdapter = this.createCallAdapter(); // 从Rrofit获取CallAdapter
            this.responseType = this.callAdapter.responseType(); // 从adapter获取返回的类型
            if (this.responseType != Response.class && this.responseType != okhttp3.Response.class) {
                this.responseConverter = this.createResponseConverter(); // 获取转换器类型
                Annotation[] var1 = this.methodAnnotations;
                int p = var1.length;

                for(int var3 = 0; var3 < p; ++var3) {
                    Annotation annotation = var1[var3];
                    // 解析url等等注解信息
                    this.parseMethodAnnotation(annotation);
                }

                if (this.httpMethod == null) {
                    throw this.methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
                } else {
                    if (!this.hasBody) {
                        if (this.isMultipart) {
                            throw this.methodError("Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
                        }

                        if (this.isFormEncoded) {
                            throw this.methodError("FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).");
                        }
                    }

                    int parameterCount = this.parameterAnnotationsArray.length;
                    this.parameterHandlers = new ParameterHandler[parameterCount];

                    for(p = 0; p < parameterCount; ++p) {
                        Type parameterType = this.parameterTypes[p];
                        if (Utils.hasUnresolvableType(parameterType)) {
                            throw this.parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType);
                        }

                        Annotation[] parameterAnnotations = this.parameterAnnotationsArray[p];
                        if (parameterAnnotations == null) {
                            throw this.parameterError(p, "No Retrofit annotation found.");
                        }
                        // 解析注解参数等信息
                        this.parameterHandlers[p] = this.parseParameter(p, parameterType, parameterAnnotations);
                    }
                        ......
                       // 一些解析参数的容错提示 
                       
                        return new ServiceMethod(this);
                    }
                }
            } else {
                 ......
                // 一些解析参数的容错提示
            }
        }

我们继续看下解析url及方法名注解和参数注解两个方法

 private void parseMethodAnnotation(Annotation annotation) {
            if (annotation instanceof DELETE) {
                this.parseHttpMethodAndPath("DELETE", ((DELETE)annotation).value(), false);
            } else if (annotation instanceof GET) {
                this.parseHttpMethodAndPath("GET", ((GET)annotation).value(), false);
            } 
            ........

 }


 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
            if (this.httpMethod != null) {
                throw this.methodError("Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod);
            } else {
                this.httpMethod = httpMethod;
                this.hasBody = hasBody;
                // 匹配注解方法中的值如:users/{user}/repos or user
                   
                if (!value.isEmpty()) {
                    int question = value.indexOf(63);
                    if (question != -1 && question < value.length() - 1) {
                        String queryParams = value.substring(question + 1);
                        Matcher queryParamMatcher = ServiceMethod.PARAM_URL_REGEX.matcher(queryParams);
                        if (queryParamMatcher.find()) {
                            throw this.methodError("URL query string \"%s\" must not have replace block. For dynamic query parameters use @Query.", queryParams);
                        }
                    }
                    // 赋值url及其中参数 
                    this.relativeUrl = value; // @GET("xxx")中的xxx
                    this.relativeUrlParamNames = ServiceMethod.parsePathParameters(value);
                }
            }
        }
 private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
            ParameterHandler<?> result = null;
            Annotation[] var5 = annotations;
            int var6 = annotations.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Annotation annotation = var5[var7];
                ParameterHandler<?> annotationAction = this.parseParameterAnnotation(p, parameterType, annotations, annotation);
                if (annotationAction != null) {
                    if (result != null) {
                        throw this.parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
                    }

                    result = annotationAction;
                }
            }

            if (result == null) {
                throw this.parameterError(p, "No Retrofit annotation found.");
            } else {
                return result;
            }
        }

parseParameterAnnotation方法太长这里就不粘了,就是根据不同类型解析对应参数,我们挑选其中一种简单看下
 if (annotation instanceof Query) {
                        // 获取Query相应值及参数 value、编码、基础类型等等
                        Query query = (Query)annotation;
                        partName = query.value();
                        encoded = query.encoded();
                        arrayComponentType = Utils.getRawType(type);
                        this.gotQuery = true;
                        if (Iterable.class.isAssignableFrom(arrayComponentType)) {
                            // 通过三种状态包括可迭代Iterable、Array、其他。最后组装成ParameterHandler供后续网络请求使用。
                            if (!(type instanceof ParameterizedType)) {
                                throw this.parameterError(p, arrayComponentType.getSimpleName() + " must include generic type (e.g., " + arrayComponentType.getSimpleName() + "<String>)");
                            } else {
                                parameterizedType = (ParameterizedType)type;
                                iterableType = Utils.getParameterUpperBound(0, parameterizedType);
                                converter = this.retrofit.stringConverter(iterableType, annotations);
                                return (new retrofit2.ParameterHandler.Query(partName, converter, encoded)).iterable();
                            }
                        } else if (arrayComponentType.isArray()) {
                            arrayComponentType = ServiceMethod.boxIfPrimitive(arrayComponentType.getComponentType());
                            valueConverter = this.retrofit.stringConverter(arrayComponentType, annotations);
                            return (new retrofit2.ParameterHandler.Query(partName, valueConverter, encoded)).array();
                        } else {
                            converter = this.retrofit.stringConverter(type, annotations);
                            return new retrofit2.ParameterHandler.Query(partName, converter, encoded);
                        }
                    }

好ServiceMethod的创建及缓存已经完成,接下来是:

OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args);

从名字很容易想到OkHttp的Call,是的!他就是OkHttp的封装!我们这里只摘取他的异步方法看下。

 public void enqueue(final Callback<T> callback) {
        Utils.checkNotNull(callback, "callback == null");
        okhttp3.Call call;
        Throwable failure;
        synchronized(this) { // 加锁
            if (this.executed) {
                throw new IllegalStateException("Already executed.");
            }

            this.executed = true; // 是否已执行
            call = this.rawCall; // 赋值rawCall用于复用
            failure = this.creationFailure;
            if (call == null && failure == null) {
                try {
                    call = this.rawCall = this.createRawCall(); // 这句比较关键,也是能抓出他就是OkHttpCall封装的证据
                } catch (Throwable var7) {
                    failure = this.creationFailure = var7;
                }
            }
        }

        if (failure != null) {
            callback.onFailure(this, failure);
        } else {
            if (this.canceled) {
                call.cancel();
            }
            // 开始执行异步操作并接回回执
            call.enqueue(new okhttp3.Callback() {
                public void onResponse(okhttp3.Call call, Response rawResponse) throws IOException {
                    retrofit2.Response response;
                    try {
                        response = OkHttpCall.this.parseResponse(rawResponse);
                    } catch (Throwable var5) {
                        this.callFailure(var5);
                        return;
                    }

                    this.callSuccess(response);
                }

                public void onFailure(okhttp3.Call call, IOException e) {
                    try {
                        callback.onFailure(OkHttpCall.this, e);
                    } catch (Throwable var4) {
                        var4.printStackTrace();
                    }

                }

                private void callFailure(Throwable e) {
                    try {
                        callback.onFailure(OkHttpCall.this, e);
                    } catch (Throwable var3) {
                        var3.printStackTrace();
                    }

                }

                private void callSuccess(retrofit2.Response<T> response) {
                    try {
                        callback.onResponse(OkHttpCall.this, response);
                    } catch (Throwable var3) {
                        var3.printStackTrace();
                    }

                }
            });
        }
    }
   private okhttp3.Call createRawCall() throws IOException {
        Request request = this.serviceMethod.toRequest(this.args);
        // 这里的call是在Retrofit创建时Builder的builde方法里OkHttpClient构造的
        okhttp3.Call call = this.serviceMethod.callFactory.newCall(request);
        if (call == null) {
            throw new NullPointerException("Call.Factory returned null.");
        } else {
            return call;
        }
    }

到此为止还没有出发调用的地方,真相就在我们接下来要看的这句代码了

serviceMethod.callAdapter.adapt(okHttpCall);

这里要结合两点:

第一点我们要知道ServiceMethod中的build方法中创建的callAdapter最终调用到了Rerofit中的

 public CallAdapter<?, ?> nextCallAdapter(@Nullable retrofit2.CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
        Utils.checkNotNull(returnType, "returnType == null");
        Utils.checkNotNull(annotations, "annotations == null");
        int start = this.adapterFactories.indexOf(skipPast) + 1;
        int i = start;

        int i;
        for(i = this.adapterFactories.size(); i < i; ++i) {
            //最关键的代码,调用实现该方法地方的get处
            CallAdapter<?, ?> adapter = ((retrofit2.CallAdapter.Factory)this.adapterFactories.get(i)).get(returnType, annotations, this);
            if (adapter != null) {
                return adapter;
            }
        }
        // 错误信息展示
        StringBuilder builder = (new StringBuilder("Could not locate call adapter for ")).append(returnType).append(".\n");
        if (skipPast != null) {
            builder.append("  Skipped:");

            for(i = 0; i < start; ++i) {
                builder.append("\n   * ").append(((retrofit2.CallAdapter.Factory)this.adapterFactories.get(i)).getClass().getName());
            }

            builder.append('\n');
        }

        builder.append("  Tried:");
        i = start;

        for(int count = this.adapterFactories.size(); i < count; ++i) {
            builder.append("\n   * ").append(((retrofit2.CallAdapter.Factory)this.adapterFactories.get(i)).getClass().getName());
        }

        throw new IllegalArgumentException(builder.toString());
    }

篇幅有点长了,这里我们看其中的一种实现,就是默认的实现。这也是我们要结合的第二点:还记得

Platform中的Android实现类吗?就是它将线程调度到主线程并返回了所需的Executor。第一点中的get方法其实就是调用到了其中的
ExecutorCallAdapterFactory类的get方法
   public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        } else {
            final Type responseType = Utils.getCallResponseType(returnType);
            return new CallAdapter<Object, Call<?>>() {
                public Type responseType() { // 返回类型
                    return responseType;
                }

                public Call<Object> adapt(Call<Object> call) { // 执行方法
                    return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
                }
            };
        }
    }

 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;
        }
        // 真正的的调用处
        public void enqueue(final Callback<T> callback) {
            Utils.checkNotNull(callback, "callback == null");
            // 用户真正传入的callback,delegate就是刚才传入的okHttpCall
            this.delegate.enqueue(new Callback<T>() {
                public void onResponse(Call<T> call, final Response<T> response) {
                    ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                        public void run() {
                            if (ExecutorCallbackCall.this.delegate.isCanceled()) {
                                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                            } else {
                                callback.onResponse(ExecutorCallbackCall.this, response);
                            }

                        }
                    });
                }

                public void onFailure(Call<T> call, final Throwable t) {
                    ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                        public void run() {
                            callback.onFailure(ExecutorCallbackCall.this, t);
                        }
                    });
                }
            });
        }

好了到这,整个流程就连贯起来了。RxJava2CallAdapterFactory也是实现了这一套与之类似。

这里我们做一下简单的汇总,Retrofit都到了哪些设置模式,不全的地方欢迎大家补充啊。

1、外观模式:Retrofit类就是一个这样的实现类,包括许多其他利害的框架也是如Glide。为了大家方便学习及使用把一些必要的东西都汇聚于此,加上详细的注释,入口就比较明了,用起来也就清晰了。

2、动态代理模式:也是Retrofit使用的比较精髓的一种。通过在create时使用该模式在解耦的同时又提供了足够的代码简洁。

3、建造者模式:其实大量的优秀框架都大量使用到了该模式,Retrofit也不例外。因为该实例构建过程配置项比较复杂庞大,使用该模式隔离了使用者对具体构建实例的过程,通过封装提高代码的复用性,根据使用者的需求快捷的构建出想要的实例对象。(变种的责任链调用使用起来更加过瘾)

4、工厂模式:如addConverterFactory、addCallAdapterFactory等处,方便阅读的同时更加方便扩展,主体只关心工作内容不关系谁来做。如addCallAdapterFactory我可以用LiveDataCallAdapterFactory/RxJava2CallAdapterFactory.create()

5、适配器模式:CallAdapter的中的适配器模式(暂可用Rxjava的、java8的、guava的 、默认的。当然还有自定义的)。适配器模式主要是为了转换OkHttpCall及方便兼容全平台。为什么要转换?因为要帮助OkHttpCall切换线程来完成请求等操作。Retrofit提供了默认的adaper用来切换线程的操作,如果用Rxjava就更简单了...。所以除了默认的一律不管了,不用默认的就自己去实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值