美文网首页
Retrofit的原理解析

Retrofit的原理解析

作者: ChristZc | 来源:发表于2022-07-21 17:08 被阅读0次

前言

上篇文章我们分析了OkHttp的原理,不难看出它更多的还是和TCP/IP打交道,做了请求和响应的处理,今天我们来介绍另外一位主人公,那就是我们的Retrofit,它更多的是对OkHttp做了一层封装,方便了我们调用接口,并且对数据进行了转化,对业务侧更加友好。
首先我们来看看它的初始化,慢慢剖析它的源码吧。

        Retrofit retrofit = new Retrofit.Builder().baseUrl(BaseUrl.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClient)
                .build();

老相识又出现了Builder,我们接着看

Retrofit.Builder()

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

代码很清楚,这里进行了平台的获取并且赋值。

Builder.baseUrl

    public Builder baseUrl(String baseUrl) {
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
    }

    public Builder baseUrl(HttpUrl baseUrl) {
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

这里也是比较简单就是对baseUrl进行赋值,返回当前的Builder对象。后面的几个基本都一样,感兴趣的可以自己追一下。

Builder.build

    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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 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());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
       //返回一个 创建的Retrofit对象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

我们接着看看Retrofit的创建,如下:

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

其实也是简单的一些属性的赋值。到这里我们简单的Retrofit创建就完成了。下面分析大头,接口的创建请求以及调用回调。’

public interface OKHttpService {
    /**
     * 登录接口demo
     */
    @FormUrlEncoded
    @POST("user/login")
    Call<ResponseBody> login(@Field("username") String num, @Field("password") String password);

我这里简单创建了个登录接口。

        OKHttpService httpService = retrofit.create(OKHttpService.class);
        httpService.login("zc", "123123").enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.i("ZC", "成功: " + Thread.currentThread());
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.i("ZC", "失败: " + Thread.currentThread());
            }
        });

接着我们通过create去创建并且发送请求,我们一步步的看下去:

create

  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable 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);
            }
            //loadServiceMethod创建的代理方法对象,其内部包含了login方法的注解参数,返回值,以及各个工厂以及各请求器转换器等等的适配操作
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

这里的invoke我们在下面分析。

动态代理模式:在程序运行期间,通过反射机制,动态创建OkhttpService.class的代理对象,并且对该对象中的方法增加一些其他操作

newProxyInstance

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
        //若interface没有重写clone(),默认的是进行一次浅拷贝,即实例对象相同,引用不同
        final Class<?>[] intfs = interfaces.clone();
        // Android-removed: SecurityManager calls
        /*
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        */

        /*
         * Look up or generate the designated proxy class.
          *生成或获取(缓存中)代理类的Class对象
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            // Android-removed: SecurityManager / permission checks.
            /*
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            */
            //通过Class对象获取构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                // BEGIN Android-removed: Excluded AccessController.doPrivileged call.
                /*
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
                */

                cons.setAccessible(true);
                // END Android-removed: Excluded AccessController.doPrivileged call.
            }
            //通过构造方法创建实例对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

getProxyClass0获取的Class对象其实是个单例模式,在第一次时会创建实例并将其存入WeakCache做缓存,之后的获取会直接从缓存中获取Class对象,至于其他一些操作,多为反射机制实例化对象常用的调用。

还有一点我们需要记住的是,InvocationHandler内部的invoke被调用是我们通过newProxyInstance()返回的代理类对象(OKHttpService的代理实现类)调用login()时,触发invoke()。

至此我们就简单的分析完了Proxy.newProxyInstance()中的源码,我们继续回到create()源码中,return代理对象,至此OKHttpService接口的代理对象就被创建了,接下来就要使用代理对象OKHttpService调用login()方法了。

调用login()时我们会调用InvocationHandler#invoke()

ServiceMethod对象实例化
一个ServiceMethod对象对应了一个网络接口中的方法,该对象中保存有方法的处理网络请求所要用到的各种参数及方法的属性注解等,阅读源码时要搞清楚serviceMethod的性质,这里调用了loadServiceMethod()我们进入方法内部看看。

loadServiceMethod

  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

同样,首先会从缓存中获取对象,为null才会创建实例对象,也是一个单例对象,在Builer()中会将解析method一些信息(参数,注解,参数注解)和retrofit对象中的属性,并保存到serviceMethod对象中。
延伸知识点(继续深追源码):ServiceMethod不仅存储了method(也就是login()方法)的参数,属性等,还存储有各种适配器,转换器,和http协议要求的一些相关check,需要结合http相关的知识来理解。这里直接给结论,就不继续追了。

HttpServiceMethod#invoke

  @Override final @Nullable ReturnT invoke(Object[] args) {
    //创建一个网络请求器,所以说Retrofit底层默认是使用okhttp实现的
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
     //将okhttpcall对象与网络请求适配器进行绑定
    return adapt(call, args);
  }

不难看出,它创建了个OkHttpCall对象,retrofit2#OkHttpCall重写了execute()和enqueue方法等,在随后的网络请求适配器调用中,就会执行此方法来通过OkHttp请求访问网络

adapt(call, args)

将创建的okHttpCall对象与serviceMethod中的网络请求适配器适配,内部return callAdapter.adapt(call);而此callAdapter还记得在哪获取的?
它是在serviceMethod.loadServiceMethod(method)内的createCallAdapter()中选择的,所以这里的引用是之前选择的网络请求适配器类对象的adapt(),我们就先看一下它默认的网络请求适配器也就是DefaultCallAdapterFactory。

DefaultCallAdapterFactory #get#CallAdapter#adapt

  @Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    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) {
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

当执行了serviceMethod.adapt(okHttpCall)时,其实(默认)调用了此处的adapt()方法,返回一个call对象。
小小整理一下:
当客户端调用login()方法时,是使用的Proxy.newProxyInstance()返回的代理实例对象httpService去调用的,并且会回调InvocationHandler中的invoke()方法,执行代理操作,最后通过adapt()返回一个call对象。

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

        public void enqueue(final Callback<T> callback) {
            Objects.requireNonNull(callback, "callback == null");
            //delegate是在实例化ExecutorCallbackCall时传递的第二个参数,对象为OkHttpCall,也就是说这里enqueue()又委托给了OkHttpCall来执行
            this.delegate.enqueue(new Callback<T>() {
                public void onResponse(Call<T> call, Response<T> response) {
                //在Android环境中运行callbackExecutor默认为MainThreadExecutor,当网络请求成功,执行切回到主线程中,回调客户端的callback对象的onResponse()方法
                    ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
                        if (ExecutorCallbackCall.this.delegate.isCanceled()) {
                            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                        } else {
                            callback.onResponse(ExecutorCallbackCall.this, response);
                        }

                    });
                }

                public void onFailure(Call<T> call, Throwable t) {
                    //失败同样也会切换到主线程去回调callback的onFailure()
                    ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
                        callback.onFailure(ExecutorCallbackCall.this, t);
                    });
                }
            });
        }

        public boolean isExecuted() {
            return this.delegate.isExecuted();
        }

        public Response<T> execute() throws IOException {
            return this.delegate.execute();
        }

        public void cancel() {
            this.delegate.cancel();
        }

        public boolean isCanceled() {
            return this.delegate.isCanceled();
        }

        public Call<T> clone() {
            return new DefaultCallAdapterFactory.ExecutorCallbackCall(this.callbackExecutor, this.delegate.clone());
        }

        public Request request() {
            return this.delegate.request();
        }
    }

调用login的时候返回了一个Call,然后调用enqueue,我们就能看的出就是调用的这里(默认),其实内部调用的是delegate.enqueue(),也就是我们上文提到过得OkHttpCall的enqueue,调用okhttp3完成请求,拿到回调并且处理Response回调。

ExecutorCallbackCall.this.callbackExecutor

这里其实还有个这个东西需要说明下,callbackExecutor默认是个啥,这里我们就可以追到

Android

  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

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

真正调用接口的实现

OkHttpCall#enqueue

  @Override public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(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 {
          //创建okhttp3.Call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(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) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }

接着追一下createRawCall()

createRawCall

  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

RequestFactory#create()

  okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args.length;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    省略...

    return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }

这里可以看到创建了个RequestBuilder,对一些属性进行了赋值,接着看get,

RequestBuilder#get()

  Request.Builder get() {
    HttpUrl url;
    HttpUrl.Builder urlBuilder = this.urlBuilder;
    if (urlBuilder != null) {
      url = urlBuilder.build();
    } else {
      // No query parameters triggered builder creation, just combine the relative URL and base URL.
      //noinspection ConstantConditions Non-null if urlBuilder is null.
      url = baseUrl.resolve(relativeUrl);
      if (url == null) {
        throw new IllegalArgumentException(
            "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
      }
    }

    RequestBody body = this.body;
    if (body == null) {
      // Try to pull from one of the builders.
      if (formBuilder != null) {
        body = formBuilder.build();
      } else if (multipartBuilder != null) {
        body = multipartBuilder.build();
      } else if (hasBody) {
        // Body is absent, make an empty body.
        body = RequestBody.create(null, new byte[0]);
      }
    }

    MediaType contentType = this.contentType;
    if (contentType != null) {
      if (body != null) {
        body = new ContentTypeOverridingRequestBody(body, contentType);
      } else {
        headersBuilder.add("Content-Type", contentType.toString());
      }
    }

    return requestBuilder
        .url(url)
        .headers(headersBuilder.build())
        .method(method, body);
  }

到这里我们就能看到Okhttp3的Request以及它的内部类Builder了,到这里就终于揭开神秘面纱,打通Retrofit和OkHttp了。后面就是构建OkHttp的request以及Call了,然后通过OkHttp的Call去请求,回调处理转换类型。这里就不再细分下去了。对于OkHttp的原理感兴趣的可以看我之前的博客。

总结一下上面的流程:

这里首先根据serviceMethod中关于login()方法的属性以及解析的注解信息创建request请求对象,最后通过return callFactory.newCall(requestBuilder.build());
callFactory
默认是OkHttpClient,我们就不在深入展示了,最终在其内部返回的是一个RealCall,有兴趣的可以进去了解一下OkHttpClient源码,到了这里,Retrofit的网络请求底层便显露在我们眼前,从这里我们就可以看到,Retrofit使用的网络底层为OkHttp
接下来退回到enqueue()方法体内,之后调用call(RealCall)对象的enqueue()来处理网络请求了,至于之后的事情,就是OkHttp底层要做的了。
最后我们使用RealCall调用enqueue()传入的Callback对象,Callback的onResponse通过parseResponse()完成数据转换。成功回调onResponse,失败回调onFailure(),最后客户端就可以看到网络的访问状况了。

相关文章

网友评论

      本文标题:Retrofit的原理解析

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