Retrofit源码解析

栏目: Java · 发布时间: 4年前

内容简介:retrofit是一种类型安全的HTTP客户端。所谓的类型安全,就是说在运行时不会报类型错误,它会在编译期检查。 要分析它的源码当然是从使用开始说起。在之前的例子中通过Retrofit.create()方法来生成网络请求对象,利用这个对象进行相关的同步或者异步请求。所以从这里开始。先关方法的含义已经写到注释里了,因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法从上面可以看出无非就是之前加载过的话就从缓存中取,没加载过的话就的重新构建并且加入到

retrofit是一种类型安全的HTTP客户端。所谓的类型安全,就是说在运行时不会报类型错误,它会在编译期检查。 要分析它的源码当然是从使用开始说起。在之前的例子中通过Retrofit.create()方法来生成网络请求对象,利用这个对象进行相关的同步或者异步请求。所以从这里开始。

public <T> T create(final Class<T> service) {
    //验证是否为接口而且是不继承其他接口的接口
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }

    //核心就是动态代理,就是创建一个对象,它会代理service(接口)中的每个方法,
    //然后把接口中的每个方法通过serviceMethod.callAdapter.adapt(okHttpCall);代替返回相应的结果
    //参数一:类加载器,参数二:动态代理代理的是哪些类,参数三
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
                //Anddroid的还是 Java 8、Java7等
                private final Platform platform = Platform.get();

                @Override public Object invoke(Object proxy, Method method, Object... args)
                        throws Throwable {
                    // If the method is a method from Object then defer to normal invocation.
                    //如果是Object类自有的方法就直接执行
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    //如果是平台中自有的方法也直接执行
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    ServiceMethod serviceMethod = loadServiceMethod(method);
                    //call就做了两件事
                    //一:生成一个真正的OKHTTP的call并且加入请求队列
                    //二:对返回结果利用之前定义的converter转换后返回给callback
                    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    //之所以会用adapter的adapt方法主要是为了线程切换(rxjava的转换),这里是把结果切回主线程
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

复制代码

先关方法的含义已经写到注释里了,因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法 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;
}
复制代码

从上面可以看出无非就是之前加载过的话就从缓存中取,没加载过的话就的重新构建并且加入到缓存中。找到方法之后则很自然的要执行这个方法,那就得是OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);通过这步把要执行的方法及参数保存到了OKHTTP的call中,当执行enqueque的时候则真正的用得到的方法和参数请求网络。 在基本使用中,构造完网络请求对象之后,就用这个对象进行实际的网络请求,比如异步的enquue。

@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();
      }
    }
  });
}
复制代码

上面代码中最重要的则是 createRawCall() ,也就是创建OKHTTP的call,然后利用这个call调用OKHTTP的enqueque来进行真正的网络请求,同时将返回值返回到callback中。 到这里已经可以拿到网络通信结果了当然是通过 parseResponse(rawResponse) 转换的最终结果,而这个转换则是通过初始化时 addConverterFactory 添加的转换器,为什么不直接返回这个okHttpCall而是还要进行下一步 return serviceMethod.callAdapter.adapt(okHttpCall); 那就得看一下OKHTTP的enqueque做了什么

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

复制代码

OKHTTP的实现类中的enqueue调用了 client.dispatcher().enqueue(),继续看这个enqueque

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}
复制代码

从这个理可以看出来如果当前发送请求的数量大于 maxRequests (当前源码数量为64),加入队列待执行,如果没到则执行,而执行的代码可以清楚的看到使用executorService().execute(call)。说明在后台线程池中进行的请求和返回。那么到这里就大致的可以推断出return adatp的作用了,那就是 线程切换 。 直接跟进去发现adapt方法是在接口类中,那么我们直接找它的实现类看看,一共有两个即 ExecutorCallAdapterFactoryDefaultCallAdapterFactory ,然后再看这两个类在那儿用的,发现是在下面这个方法中调用的

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor != null) {
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
  return DefaultCallAdapterFactory.INSTANCE;
}
复制代码

而这个方法有又是retrofit的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> 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);
  }
}
复制代码

而在这个方法中我们看到需要向方法中传一个callbackExecutor,而这个executor从字面看就是与平台相关的,那么Android平台的是什么样子呢

static class Android extends Platform {
  @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);
    }
  }
}
复制代码

从handler.post我们一下子就豁然开朗了。 大框架已经已经说完了,那么那些注解什么时候用的呢,那就得从构造方法和参数入手了,仔细看一下

ServiceMethod.Builder<>(this, method).build();
public ServiceMethod build() {
  callAdapter = createCallAdapter();
  responseType = callAdapter.responseType();
  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError("'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  responseConverter = createResponseConverter();

  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }

  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }

  if (!hasBody) {
    if (isMultipart) {
      throw methodError(
          "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
      throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
          + "request body (e.g., @POST).");
    }
  }

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

  if (relativeUrl == null && !gotUrl) {
    throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
  }
  if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError("Non-body HTTP method cannot contain @Body.");
  }
  if (isFormEncoded && !gotField) {
    throw methodError("Form-encoded method must contain at least one @Field.");
  }
  if (isMultipart && !gotPart) {
    throw methodError("Multipart method must contain at least one @Part.");
  }

  return new ServiceMethod<>(this);
}
复制代码

从上面的源码可以看出首先创建了最后一步需要的callAdapter,然后创建ResponseConverter,也就是通常的将结果转化为Gson等的转换器。然后解析方法注解parseMethodAnnotation(annotation);、解析参数注解parseParameter(p, parameterType, parameterAnnotations)。最后生成的请求和返回所需要的全部参数如下

ServiceMethod(Builder<R, T> builder) {
  this.callFactory = builder.retrofit.callFactory();
  this.callAdapter = builder.callAdapter;
  this.baseUrl = builder.retrofit.baseUrl();
  this.responseConverter = builder.responseConverter;
  this.httpMethod = builder.httpMethod;
  this.relativeUrl = builder.relativeUrl;
  this.headers = builder.headers;
  this.contentType = builder.contentType;
  this.hasBody = builder.hasBody;
  this.isFormEncoded = builder.isFormEncoded;
  this.isMultipart = builder.isMultipart;
  this.parameterHandlers = builder.parameterHandlers;
}
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

共享经济

共享经济

[美] 罗宾•蔡斯 / 王芮 / 浙江人民出版社 / 2015-9-25 / 59.90元

[内容简介]  在当今这个稀缺的世界里,人人共享组织可以创造出富足。通过利用已有的资源,如有形资产、技术、网络、设备、数据、经验和流程等,这些组织可以以指数级成长。人人共享重新定义了我们对于资产的理解:它是专属于个人的还是大众的;是私有的还是公有的;是商业的还是个人的,并且也让我们对监管、保险以及管理有了重新的思索。  在这本书中,罗宾与大家分享了以下观点:  如何利用过剩......一起来看看 《共享经济》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换