美文网首页
Retrofit2 源码解析-探究接口如何创建实例

Retrofit2 源码解析-探究接口如何创建实例

作者: 844b9a3a3a68 | 来源:发表于2018-11-07 14:40 被阅读26次

    今天突然想到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?");
                }
            }
    

    相关文章

      网友评论

          本文标题:Retrofit2 源码解析-探究接口如何创建实例

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