Retrofit源码分析

1、Retrofit

根据官网的描述:一种类型安全的java和android的http客户端。

类型安全:指的是在编译的时候就会把类型错误暴露出来,不会在运行的时候抛出类型错误。

public interface GitHubService
{
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>

}

使用Retrofit首先定义一个服务接口

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val retrofit:Retrofit = Retrofit.Builder()
        .baseUrl("https://aip.github.com/")
        .build()

        val service = retrofit.create(GitHubService::class.java)

        val repos: Call<List<Repo>> = service.listRepos("octocat")

        repos.enqueue(object :Callback<List<Repo>?>{
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                TODO("Not yet implemented")
            }

            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                TODO("Not yet implemented")
            }
        })

    }
}

Retrofit的基本get请求调用如上,可见如OkHttp一样,主要的入口是enqueue()的方法,追踪enqueue可以发现是一个接口方法。所以最终的实现是由repos对象提供的。repos对象由service里面的listRepos()方法提供,追踪发现是我们在最开始定义接口,故所以,最终的业务入口可以成功定位出来了,就是:

 retrofit.create(GitHubService::class.java)

1.1、create()

   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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });//动态代理

validateServiceInterface()方法主要是对接口的规范性做检查.PS:里面有个参数能控制是否进行激进检查,激进检查可以把所以的接口方法都在初始化的时候检查,涉及到反射,可快速测试,但是有可能影响性能。

剩下的所有的代码其实都是调用newProxyInstance()的方法。该方法也是实现了retrofit的核心,动态代理功能。

何为代理?代理,指的是retrofit创建一个类继承我们的接口,并且会实现我们接口中的方法,也就是说retrofit代理了我们所以的接口。
何为动态?动态,指的是在该类是在运行的时候创建,而不是编译时。

1.2、newProxyInstance()

该方法一共有三个参数: ClassLoader,Class<?>[],InvocationHandler
其中一是ClassLoader,任意一ClassLoader都可用,Class<?>[]为接口集合,即我们传进的接口,第三个匿名内部类InvocationHandler。所以如何实现匿名内部类,就是如果实现retrofit的动态代理。

具体实现接口方法的模式,大概是将InvocationHandler这个内部类的对象,交给代理类(运行过程中继承我们接口,创建的类),并且通过我们接口中的方法来实际调用InvocationHandler#invoke。可以当成代理类是载体,内部类InvocationHandler#invoke是实际的干活人。

1.3、InvocationHandler#invoke()

 @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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }

第一个if里面的逻辑,检查是否为Object方法,如果是,直接调用。也就是如果我们接口中的方法是系统的方法,如toString等,Retrofit就不代理,直接调用。

第二个if里面的逻辑,不代理JAVA8里面的默认方法。

最后一行返回了一个 loadServiceMethod(method)#invoke();

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

 @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

loadServiceMethod()调用 HttpServiceMethod的parseAnnotations()实现了他本身的invoke()方法。创建了一个retrofit的OkHttpCall对象,然后用过adapt()在做了某些操作。我们先来看看OkHttpCall是个怎么样的对象。

我们可以发现OkHttpCall继承于Call接口,并且实现了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 {
          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
        }
      }

通过上述代码,我们不难发现,enqueue()的发方法,创建了一个okhttp的Call

okhttp3.Call call;

并却,在内部实现了okhttp3的enqueue()方法

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

到这里,Retrofit的基本工作就做完了,剩下正真的网络请求就交给OkHttp去做了。

附带一篇Retrofit深度解析好文:https://www.jianshu.com/p/0c055ad46b6c

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。