Retrofit2 源碼解析-探究接口如何創建實例

今天突然想到Retrofit2創建Service需要傳遞一個接口,但是我們都知道接口是不能直接生成實例的,那麼Retrofit2是如何做到的呢?帶着疑惑,看一波源碼。

  //創建實例
 retrofit.create(VideoApis.class);
跟進create方法:
    //此方法需要一個Class類
    public <T> T create(final Class<T> service) {
        //對傳入的Class進行校驗
        Utils.validateServiceInterface(service);
        if (this.validateEagerly) {
            this.eagerlyValidateMethods(service);
        }

        return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
            private final Platform platform = Platform.get();

            public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
                if (method.getDeclaringClass() == Object.class) {
                    return method.invoke(this, args);
                } else if (this.platform.isDefaultMethod(method)) {
                    return this.platform.invokeDefaultMethod(method, service, proxy, args);
                } else {
                    ServiceMethod serviceMethod = Retrofit.this.loadServiceMethod(method);
                    OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            }
        });
    }
一進入create就調用了一個驗證方法 Utils.validateServiceInterface(service);看下源碼做了什麼事情:
    static <T> void validateServiceInterface(Class<T> service) {
        //首先驗證此類是否是接口,不是接口直接拋出異常。
        if (!service.isInterface()) {
            throw new IllegalArgumentException("API declarations must be interfaces.");
        //繼續判斷此類是否是獨立的接口類,如果有繼承其他接口則拋出異常。
        } else if (service.getInterfaces().length > 0) {
            throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
        }
    }
返回源碼繼續分析校驗通過過後的代碼:
        //這裏直接return了,後面的實例是使用了動態代理獲取了接口的實例。。。
        return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
            private final Platform platform = Platform.get();

            public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
                if (method.getDeclaringClass() == Object.class) {
                    return method.invoke(this, args);
                } else if (this.platform.isDefaultMethod(method)) {
                    return this.platform.invokeDefaultMethod(method, service, proxy, args);
                } else {
                    //前面可以忽略,這裏會走此方法
                    ServiceMethod serviceMethod = Retrofit.this.loadServiceMethod(method);
                    //這裏主要是利用源方法的信息,包裝在ServiceMethod中,然後連帶參數一併傳遞到OkHttpCall,構建出一個OkHttpCall的實例,通過代理類執行接口中定義的方法。
                    OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            }
        });
此時我們已經知道Retrofit是通過動態代理,最終使用的okhttp的實例來執行接口中的方法,順便追蹤下ServiceMethod 的出處:
    //serviceMethodCache 是定義的一個緩存Map
    private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap();
    ...
    ServiceMethod loadServiceMethod(Method method) {
        Map var3 = this.serviceMethodCache;
        synchronized(this.serviceMethodCache) {
            ServiceMethod result = (ServiceMethod)this.serviceMethodCache.get(method);
            if (result == null) {
                //主要看result的創建
                result = (new retrofit2.ServiceMethod.Builder(this, method)).build();
                this.serviceMethodCache.put(method, result);
            }

            return result;
        }
    }
通過build構建ServiceMethod的實例,期間做了很多驗證操作,包括註解是否合法,等等。
        public ServiceMethod build() {
            this.callAdapter = this.createCallAdapter();
            this.responseType = this.callAdapter.responseType();
            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];
                    //將註解解析
                    this.parseMethodAnnotation(annotation);
                }
                //如果沒有指定http請求方式,拋出異常
                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);
                    }

                    if (this.relativeUrl == null && !this.gotUrl) {
                        throw this.methodError("Missing either @%s URL or @Url parameter.", this.httpMethod);
                    } else if (!this.isFormEncoded && !this.isMultipart && !this.hasBody && this.gotBody) {
                        throw this.methodError("Non-body HTTP method cannot contain @Body.");
                    } else if (this.isFormEncoded && !this.gotField) {
                        throw this.methodError("Form-encoded method must contain at least one @Field.");
                    } else if (this.isMultipart && !this.gotPart) {
                        throw this.methodError("Multipart method must contain at least one @Part.");
                    } else {
                        return new ServiceMethod(this);
                    }
                }
            } else {
                throw this.methodError("'" + Utils.getRawType(this.responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?");
            }
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章