网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

Retrofit是一个基于AOP思想,对RestfulApi注解进行动态代理的网络框架;今天我们就来探讨下实现原理,一起进步。


前言

Retrofit是一个基于AOP思想,对RestfulApi注解进行动态代理的网络框架;

今天我们就来探讨下实现原理,一起进步

一、使用Retrofit

1、包引用

gradle文件中引用retrofit

compile 'com.squareup.retrofit2:retrofit:2.3.0' 
    compile 'com.squareup.retrofit2:retrofit-converters:2.3.0' 
    compile 'com.squareup.retrofit2:retrofit-adapters:2.3.0'

    如果需要使用更多扩展功能,比如gson转换,rxjava适配等,可以视自己需要继续添加引用;

    compile 'com.squareup.retrofit2:converter-gson:2.3.0' 
        compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

      如果现有的扩展包不能满足需要,还可以自己扩展converter,adapter等;

      2、定义接口

      Retrofit要求定义一个网络请求的接口,接口函数里要定义url路径、请求参数、返回类型;

      public interface INetApiService { 
          @GET("/demobiz/api.php") 
          Call<BizEntity> getBizInfo(@Query("id") String id); 
      }

        在这个接口定义中,用注解@GET("/demobiz/api.php")声明了url路径,用注解@Query("id") 声明了请求参数;

        最重要的是,用Call声明了返回值是一个Retrofit的Call对象,并且声明了这个对象处理的数据类型为BizEntity,BizEntity是我们自定义的数据模型;

        3、依次获得Retrofit对象、接口实例对象、网络工作对象

        首先,需要新建一个retrofit对象;

        然后,根据上一步的接口,实现一个retrofit加工过的接口对象;

        最后,调用接口函数,得到一个可以执行网络访问的网络工作对象;

        //新建一个Retrofit对象 
        Retrofit retrofit=new Retrofit.Builder() 
        .baseUrl(Config.DOMAIN)//要访问的网络地址域名,如http://www.zhihu.com 
        .addConverterFactory(GsonConverterFactory.create()) 
        .build(); 
        ... 
        //用retrofit加工出对应的接口实例对象 
        INetApiService netApiService= retrofit.create(INetApiService.class); 
        //可以继续加工出其他接口实例对象 
        IOtherService otherService= retrofit.create(IOtherService.class); 
        ··· 
        //调用接口函数,获得网络工作对象 
        Call<BizEntity> callWorker= netApiService.getBizInfo("id001");

          这个复杂的过程下来,最终得到的callWorker对象,才可以执行网络访问。

          4、访问网络数据

          用上一步获取的worker对象,执行网络请求

          callWorker.enqueue(new Callback<BizEntity>() { 
                      @Override 
                      public void onResponse(Call<BizEntity> call, Response<BizEntity> response) {...} 
                      @Override 
                      public void onFailure(Call<BizEntity> call, Throwable t) {...} 
                  });

            在回调函数里,取得我们需要的BizEntity数据对象

            二、Retrofit实现原理

            1、Retrofit对象的构建就是简单的builder模式,直接看create

            //Retrofit.java 
            public <T> T create(final Class<T> service) { 
                //验证 
                validateServiceInterface(service); 
                return (T) 
                    //动态代理 
                    Proxy.newProxyInstance( 
                    service.getClassLoader(), //类加载器 
                    new Class<?>[] {service}, //一组接口 
                    new InvocationHandler() { 
                        //判断androidjvm平台及其版本 
                        private final Platform platform = Platform.get(); 
                        @Override 
                        public Object invoke(Object proxy, Method method, Object[] args){ 
                            //如果该方法是Object的方法,直接执行不用管 
                            if (method.getDeclaringClass() == Object.class) { 
                                return method.invoke(this, args); 
                            } 
                            //isDefaultMethod:检查是否是java8开始支持的接口默认方法 
                            return platform.isDefaultMethod(method) 
                                ? platform.invokeDefaultMethod(method, service, proxy, args) 
                                : loadServiceMethod(method).invoke(args); //我们关注这里 
                        } 
                    }); 
            }

              Proxy.newProxyInstance动态代理,运行期会生成一个类(字节码)如$ProxyN,实现传入的接口即WanApi,重写接口方法然后转发给InvocationHandler的invoke

              class $ProxyN extends Proxy implements WanApi{ 
                  Call<WanArticleBean> articleList(@Path("page") int page){ 
                      //转发给invocationHandler 
                      invocationHandler.invoke(this,method,args); 
                  } 
              }

                2、validateServiceInterface验证逻辑

                //Retrofit.java 
                private void validateServiceInterface(Class<?> service) { 
                    //检查:WanApi不是接口就抛异常... 
                    //检查:WanApi不能有泛型参数,不能实现其他接口... 
                    if (validateEagerly) { //是否进行严格检查,默认关闭 
                        Platform platform = Platform.get(); 
                        for (Method method : service.getDeclaredMethods()) { //遍历WanApi方法 
                            //不是默认方法,并且不是静态方法 
                            if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) { 
                                //把方法提前加载进来(检查下有没有问题) 
                                loadServiceMethod(method); 
                            } 
                        } 
                    } 
                }

                  如果开了validateEagerly,会一次性把接口WanApi的所有方法都检查一遍并加载进来,可以在debug模式下开启,提前发现错误写法,比如在@GET请求设置了@Body这种错误就会抛出异常:

                  java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body.

                   3、loadServiceMethod

                  然后是loadServiceMethod(method).invoke(args),看名字可知是先找方法,然后执行

                  //Retrofit.java 
                  //缓存,用了线程安全ConcurrentHashMap 
                  final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); 
                  ServiceMethod<?> loadServiceMethod(Method method) { 
                      ServiceMethod<?> result = serviceMethodCache.get(method); 
                      //WanApi的articleList方法已缓存,直接返回 
                      if (result != null) return result; 
                      synchronized (serviceMethodCache) { 
                          result = serviceMethodCache.get(method); 
                          if (result == null) { 
                              //解析articleList的注解,创建ServiceMethod并缓存起来 
                              result = ServiceMethod.parseAnnotations(this, method); 
                              serviceMethodCache.put(method, result); 
                          } 
                      } 
                      return result; 
                  }

                    跟进ServiceMethod.parseAnnotations

                    //ServiceMethod.java 
                    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { 
                        //1. 
                        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); 
                        //检查:articleList方法返回类型不能用通配符和void... 
                        //2. 
                        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); 
                    }

                      4、 RequestFactory.parseAnnotations

                      //RequestFactory.java 
                      static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { 
                          return new Builder(retrofit, method).build(); 
                      } 
                      class Builder { 
                          RequestFactory build() { 
                              //解析方法注解如GET 
                              for (Annotation annotation : methodAnnotations) { 
                                  parseMethodAnnotation(annotation); 
                              } 
                              //省略各种检查... 
                              //解析参数注解如Path 
                              int parameterCount = parameterAnnotationsArray.length; 
                              parameterHandlers = new ParameterHandler<?>[parameterCount]; 
                              for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) { 
                                  parameterHandlers[p] = 
                                      parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter); 
                              } 
                              //省略各种检查... 
                              return new RequestFactory(this); 
                          } 
                      }

                        得到RequestFactory后, HttpServiceMethod.parseAnnotations,HttpServiceMethod负责适配和转换处理,将接口方法的调用调整为HTTP调用

                        //HttpServiceMethod.java 
                        //ResponseT响应类型如WanArticleBean,ReturnT返回类型如Call 
                        static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( 
                            Retrofit retrofit, Method method, RequestFactory requestFactory) { 
                            //省略kotlin协程逻辑... 
                            Annotation[] annotations = method.getAnnotations(); 
                            //遍历找到合适的适配器 
                            CallAdapter<ResponseT, ReturnT> callAdapter = 
                                createCallAdapter(retrofit, method, adapterType, annotations); 
                            //得到响应类型,如WanArticleBean 
                            Type responseType = callAdapter.responseType(); 
                            //遍历找到合适的转换器 
                            Converter<ResponseBody, ResponseT> responseConverter = 
                                createResponseConverter(retrofit, method, responseType); 
                            okhttp3.Call.Factory callFactory = retrofit.callFactory; 
                            return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); 
                        }

                          5、最终返回了一个CallAdapted,看到CallAdapted

                          //CallAdapted extends HttpServiceMethod extends ServiceMethod 
                          class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { 
                              private final CallAdapter<ResponseT, ReturnT> callAdapter; 
                              CallAdapted( 
                                  RequestFactory requestFactory, 
                                  okhttp3.Call.Factory callFactory, 
                                  Converter<ResponseBody, ResponseT> responseConverter, 
                                  CallAdapter<ResponseT, ReturnT> callAdapter) { 
                                  super(requestFactory, callFactory, responseConverter); 
                                  this.callAdapter = callAdapter; 
                              } 
                              @Override 
                              protected ReturnT adapt(Call<ResponseT> call, Object[] args) { 
                                  //适配器 
                                  return callAdapter.adapt(call); 
                              } 
                          }

                            回到Retrofit.Builder

                            //Retrofit.Builder.java 
                            public Retrofit build() { 
                                Executor callbackExecutor = this.callbackExecutor; 
                                //如果没设置线程池,则给android平台设置一个默认的MainThreadExecutor(用Handler将回调切回主线程) 
                                if (callbackExecutor == null) { 
                                    callbackExecutor = platform.defaultCallbackExecutor(); 
                                } 
                                List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); 
                                //添加默认的DefaultCallAdapterFactory 
                                callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); 
                            }

                              DefaultCallAdapterFactory这个工厂创建具体的CallAdapter实例

                              //DefaultCallAdapterFactory.java 
                              public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { 
                                  final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType); 
                                  //如果指定了SkipCallbackExecutor注解,就表示不需要切回主线程 
                                  final Executor executor = 
                                      Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) 
                                      ? null 
                                      : callbackExecutor; 
                                  return new CallAdapter<Object, Call<?>>() { 
                                      @Override 
                                      public Type responseType() { 
                                          return responseType; 
                                      } 
                                      @Override 
                                      public Call<Object> adapt(Call<Object> call) { 
                                          //默认情况下,返回用主线程池包装的Call,他的enqueue会使用主线程池的execute 
                                          return executor == null ? call : new ExecutorCallbackCall<>(executor, call); 
                                      } 
                                  }; 
                              }

                                6、invoke

                                前边loadServiceMethod得到了CallAdapted,然后执行invoke,实现在父类HttpServiceMethod里,

                                //HttpServiceMethod.java 
                                final ReturnT invoke(Object[] args) { 
                                    //终于见到okhttp了! 
                                    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); 
                                    return adapt(call, args); 
                                } 
                                class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { 
                                    private final CallAdapter<ResponseT, ReturnT> callAdapter; 
                                    @Override 
                                    protected ReturnT adapt(Call<ResponseT> call, Object[] args) { 
                                        //用前边得到的适配器,把OkHttpCall包成ExecutorCallbackCall 
                                        return callAdapter.adapt(call); 
                                    } 
                                }

                                  然后是请求入队,ExecutorCallbackCall.enqueue -> OkHttpCall.enqueue,

                                  //ExecutorCallbackCall.java 
                                  void enqueue(final Callback<T> callback) { 
                                      delegate.enqueue( 
                                          new Callback<T>() { 
                                              @Override 
                                              public void onResponse(Call<T> call, final Response<T> response) { 
                                                  //将回调切回主线程 
                                                  callbackExecutor.execute( 
                                                      () -> { 
                                                          callback.onResponse(ExecutorCallbackCall.this, response); 
                                                      }); 
                                                  //... 
                                              } 
                                              @Override 
                                              public void onFailure(Call<T> call, final Throwable t) {} 
                                          }); 
                                  } 
                                  //OkHttpCall.java 
                                  void enqueue(final Callback<T> callback) { 
                                      //okhttp逻辑 
                                      okhttp3.Call call; 
                                      call.enqueue(new okhttp3.Callback() { 
                                          void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { 
                                              callback.onResponse(OkHttpCall.this, response); 
                                          } 
                                      }) 
                                  }

                                    到此整个流程就通了

                                    二、功能扩展

                                    1、OkHttpClient

                                    Retrofit使用OkHttpClient来实现网络请求,这个OkHttpClient虽然不能替换为其他的网络执行框架比如Volley,但是Retrofit允许我们使用自己扩展OkHttpClient,一般最常扩展的就是Interceptor拦截器了;

                                    OkHttpClient mClient = new OkHttpClient.Builder() 
                                                    .addInterceptor(new Interceptor() { 
                                                        @Override 
                                                        public Response intercept(Chain chain) throws IOException { 
                                                            try { 
                                                                Request.Builder builder = chain.request().newBuilder(); 
                                                                builder.addHeader("Accept-Charset", "UTF-8"); 
                                                                builder.addHeader("Accept", " application/json"); 
                                                                builder.addHeader("Content-type", "application/json"); 
                                                                Request request = builder.build(); 
                                                                return chain.proceed(request); 
                                                            } catch (Exception e) { 
                                                                e.printStackTrace(); 
                                                            } 
                                                            return null; 
                                                        } 
                                                    }).build(); 
                                    Retrofit retrofit = new Retrofit.Builder() 
                                                    .baseUrl(Config.DOMAIN) 
                                                    .addConverterFactory(GsonConverterFactory.create()) 
                                                    .client(mClient) 
                                                    .build();

                                      2、addConverterFactory

                                      扩展的是对返回的数据类型的自动转换,把一种数据对象转换为另一种数据对象;

                                      评论 0

                                      暂无评论
                                      0
                                      0
                                      0
                                      立即
                                      投稿
                                      发表
                                      评论
                                      返回
                                      顶部