美文网首页
Retrofit2+rxjava2源码解析(一):Retrofi

Retrofit2+rxjava2源码解析(一):Retrofi

作者: CDF_cc7d | 来源:发表于2018-08-08 15:37 被阅读0次

    背景

    最近闲来无事,突然有了兴致想写一篇文章。之前一直在用retrofit2+rxjava2的网络框架,对里面的实现逻辑一直很好奇,翻了一遍网上的源码解析,基本上都是拆开单独的解析。于是花了差不多有一周的时间将里面的实现逻辑整理了一遍。
    第一次写简书,排版问题请多见谅。


    retrofit2的实现原理

    retrofit2严格意义上说其实并不算是一个网络框架,因为里面发起网络请求用的依然是OKHttp。那么retrofit2到底是个什么?请随我仔细阅读以下的源码应该就能知道了。

    话不多说先上代码:
    1、定义了接口,然后通过注解的方式封装了地址和请求参数

    /**
     * Created by chendanfeng on 2018/3/19.
     * 定义的请求服务器的API的接口
     */
    public interface APIFunction {
        /**
         * 登录请求
         * @param map 请求参数
         * @return
         */
        @POST(HttpConfig.REQUEST_LOGIN)
        Call<ResponseBean<String>> login(@Body Map<String,Object> map);
    
    }
    

    上图可以看出注解主要用了@POST和@Body。@POST代表的是请求方式是post,@Body代表的是请求体

    2、初始化retrofit

            //共通参数拦截器
            HeaderParamInterceptor commonParamInterceptor = new HeaderParamInterceptor();
    
            // 初始化okhttp
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(commonParamInterceptor)
                    .build();
    
            // 初始化Retrofit
            mRetrofit = new Retrofit.Builder()
                    .client(client)
                    .baseUrl(HttpConfig.IP)
                    .addConverterFactory(GsonConverterFactory.create())//添加gson转换器
                    .build();
    
    
            // 初始化Service
            mApiFunction = mRetrofit.create(APIFunction.class);
    

    2.1 先看下Retrofit的Builder方法:

        Builder(Platform platform) {
          this.platform = platform;
          // Add the built-in converter factory first. This prevents overriding its behavior but also
          // ensures correct behavior when using converters that consume all types.
          converterFactories.add(new BuiltInConverters());
        }
    
        public Builder() {
          this(Platform.get());
        }
    
    class Platform {
      private static final Platform PLATFORM = findPlatform();
    
      static Platform get() {
        return PLATFORM;
      }
    
      //因为是Android设备,所以这里返回的肯定是Android对象
      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();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
      }
      ...代码省略...
    
      static class Android extends Platform {
            ...代码省略...
      }
    }
    

    请记住此时返回的Android对象,之后会有用处。

    2.2 然后着重看下retrofit2的build方法:

        /**
         * Create the {@link Retrofit} instance using the configured values.
         * <p>
         * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
         * OkHttpClient} will be created and used.
         */
        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();
          }
    
          // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
      }
    

    看源码发现:
    如果没有callFactory的话就会new出一个OkHttp,换句话说如果OkHttp没有什么特殊要求的话,在初始化retrofit的时候client方法其实可以不需要调用。

    另外这里的platform就是Android对象,下面这段便是Android类的方法,所以build方法里面的callbackExecutor便是MainThreadExecutor对象,adapterFactories所add进去的CallAdapter.Factory就是ExecutorCallAdapterFactory对象。

        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
          if (callbackExecutor == null) throw new AssertionError();
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
    

    2.3 最后看一下Retrofit的create方法:

      public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        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)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    2.3.1.首先需要预加载接口中所有的方法

      private void eagerlyValidateMethods(Class<?> service) {
        Platform platform = Platform.get();
        for (Method method : service.getDeclaredMethods()) {
          if (!platform.isDefaultMethod(method)) {
            loadServiceMethod(method);
          }
        }
      }
    
      ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    

    2.3.2.返回了一个Proxy.newProxyInstance动态代理对象

        /**
         * 登录请求
         * @param map 请求参数
         * @return
         */
        @POST(HttpConfig.REQUEST_LOGIN)
        Call<ResponseBean<String>> login(@Body Map<String,Object> map);
    

    以上面这个接口为例,当调用login的接口时,动态代理会进行拦截,然后调用invoke方法。

    2.3.3.那么来看一下invoke方法里面到底有什么操作吧

    • 主要其实就是三步:
      (1).loadServiceMethod方法:判断下当前serviceMethodCache中有没有指定的method,如果没有就创建个。
      (2).初始化OkHttpCall
      (3).调用servicemethod的callAdapter对象的adapt方法

    (1).那么就来看下ServiceMethod的Builder方法了:

        public ServiceMethod build() {
          callAdapter = createCallAdapter();
          ...省略...
          //通过之前传入的gson转换器工厂创建gson的转换器
          responseConverter = createResponseConverter();
    
          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }
          ...省略...
    
          //将所有的注解归类组成一个ParameterHandler的数组
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0; p < parameterCount; p++) {
            Type parameterType = parameterTypes[p];
            if (Utils.hasUnresolvableType(parameterType)) {
              throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
                  parameterType);
            }
    
            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
            if (parameterAnnotations == null) {
              throw parameterError(p, "No Retrofit annotation found.");
            }
    
            parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
          }
          ...省略...
          return new ServiceMethod<>(this);
        }
    

    先看createCallAdapter->callAdapter->nextCallAdapter->adapterFactory.get()方法。还记得之前的ExecutorCallAdapterFactory对象么,就是这里的adapterFactories.get(i),下图便是ExecutorCallAdapterFactory的get方法。

      @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);
          }
        };
      }
    

    所以serviceMethod对象里面的callAdapter便是在这里初始化的,可以先记下这里的adapt方法,后面会用到

    parseMethodAnnotation就是对每个注解进行解析,将注解转换成网络请求所需的各种配置。一开始的@POST和@Body便是在这个方法里面进行解析的,具体可以自行查看源码, 这里不做分析。

    (2).初始化OkHttpCall
    这一步就是将serviceMethod传入
    (3).调用serviceMethod的callAdapter对象的adapt方法
    这里的serviceMethod.callAdapter就是之前创建ServiceMethod时,返回的callAdapter方法

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

    返回的是一个ExecutorCallbackCall对象,并且将OkHttpCall对象传入

    到此为止,retrofit2的初始化工作已经全部完成,那么接下来就看下是如何执行网络请求的

    3.进行网络请求操作
    先上代码:

    RetrofitFactory.getInstance().API().login(map).enqueue(new Callback<ResponseBean<String>>() {
                @Override
                public void onResponse(Call<ResponseBean<String>> call, Response<ResponseBean<String>> response) {
    
                }
    
                @Override
                public void onFailure(Call<ResponseBean<String>> call, Throwable t) {
    
                }
            });
    

    直接进入正题,前面讲到最后返回的是ExecutorCallbackCall,正是现在这个对象将要执行enqueue方法,那么为什么调用login的接口会返回ExecutorCallbackCall对象呢,就是之前提到过的动态代理调用了invoke方法返回的。

    3.1 那么进入ExecutorCallbackCall的代码:

      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;
        }
    
        @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);
                }
              });
            }
          });
        }
    
        @Override public boolean isExecuted() {
          return delegate.isExecuted();
        }
    
        @Override public Response<T> execute() throws IOException {
          return delegate.execute();
        }
    
        @Override public void cancel() {
          delegate.cancel();
        }
    
        @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();
        }
      }
    

    其实ExecutorCallbackCall并没有做什么事情,处理事情全部交给了代理来做,那么这个代理是什么呢。没错,就是ExecutorCallbackCall初始化的时候传入的OkHttpCall对象

    3.2 接下来进入OkHttpCall的代码
    终于进入到了关键的地方,代码有几百行,我们只关心enqueue方法:

      @Override public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");
    
        okhttp3.Call call;
        Throwable failure;
    
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          call = rawCall;
          failure = creationFailure;
          if (call == null && failure == null) {
            try {
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
    
        if (canceled) {
          call.cancel();
        }
    
        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
              throws IOException {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            callSuccess(response);
          }
    
          @Override public void onFailure(okhttp3.Call call, IOException e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callSuccess(Response<T> response) {
            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    
      //创建了Okhttp3.Call对象,这个对象才是真正进行网络请求的
      private okhttp3.Call createRawCall() throws IOException {
        //将之前组装好的ParameterHandler数组拿过来,组成完成的httpUrl
        Request request = serviceMethod.toRequest(args);
        //这个地方的callFactory便是okHttpClient
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    

    通过createRawCall方法创建出OKhttp的call对象,然后通过call对象进行网络请求(OKHttp3的实现原理本文暂不解析,以后有机会再给大家发一篇)。

    3.3 网络请求回调处理
    上面说了网络请求是通过OkHttp的call对象进行的,那么回调自然也就调用Okhttp的call对象的回调方法。
    通过3.2发现call对象的回调方法回来以后,调用了callback的方法,那么这个callback是什么呢。我们把代码返回到ExecutorCallbackCall里面去:

          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);
                }
              });
            }
          });
    

    这里面的callbackExecutor就是2.2里面new出的MainThreadExecutor对象,再来看下MainThreadExecutor的代码:

        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
    

    看到这里恍然大悟,终于明白了为什么明明enqueue是个异步操作,返回参数以后可以直接修改UI,原来就在这里切换回到主线程了。

    总结

    retrofit2其实就是将Java接口以及对应的注解翻译成一个HttpURL,然后通过OkHttp进行网络请求。

    下一篇给大家带来rxjava2的解析。

    相关文章

      网友评论

        本文标题:Retrofit2+rxjava2源码解析(一):Retrofi

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