当前位置: 代码迷 >> 综合 >> Retrofit2.0源码解析
  详细解决方案

Retrofit2.0源码解析

热度:83   发布时间:2024-01-05 06:01:21.0

怎么使用就不详述了,我们主要来看原理。

  1. 得到retrofit对象
    我们首先通过建造者模式获得retrofit实例
    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());}public Builder baseUrl(HttpUrl baseUrl) {checkNotNull(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;}/** Add converter factory for serialization and deserialization of objects. */public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(checkNotNull(factory, "factory == null"));return this;}public Builder client(OkHttpClient client) {return callFactory(checkNotNull(client, "client == null"));}/*** Add a call adapter factory for supporting service method return types other than {@link* Call}.*/public Builder addCallAdapterFactory(CallAdapter.Factory factory) {adapterFactories.add(checkNotNull(factory, "factory == null"));return this;}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);}}
} 

在构造器中,首先获得当前设备的的平台信息,并把内置的BuiltInConverters添加到工厂集合,主要作用是使用多种converters时能够找到可以消耗该类型的转化器;
我们来看Platform这个类:

class Platform {
    private static final Platform PLATFORM = findPlatform();static Platform get() {return PLATFORM;}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) {}try {Class.forName("org.robovm.apple.foundation.NSObject");return new IOS();} catch (ClassNotFoundException ignored) {}return new Platform();}Executor defaultCallbackExecutor() {return null;}CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {if (callbackExecutor != null) {return new ExecutorCallAdapterFactory(callbackExecutor);}return DefaultCallAdapterFactory.INSTANCE;}boolean isDefaultMethod(Method method) {return false;}Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)throws Throwable {throw new UnsupportedOperationException();}@IgnoreJRERequirement // Only classloaded and used on Java 8.static class Java8 extends Platform {
    @Override boolean isDefaultMethod(Method method) {return method.isDefault();}@Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,Object... args) throws Throwable {// Because the service interface might not be public, we need to use a MethodHandle lookup// that ignores the visibility of the declaringClass.Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);constructor.setAccessible(true);return constructor.newInstance(declaringClass, -1 /* trusted */).unreflectSpecial(method, declaringClass).bindTo(object).invokeWithArguments(args);}}static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {return new MainThreadExecutor();}@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {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);}}}static class IOS extends Platform {
    @Override public Executor defaultCallbackExecutor() {return new MainThreadExecutor();}@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);}static class MainThreadExecutor implements Executor {
    private static Object queue;private static Method addOperation;static {try {// queue = NSOperationQueue.getMainQueue();Class<?> operationQueue = Class.forName("org.robovm.apple.foundation.NSOperationQueue");queue = operationQueue.getDeclaredMethod("getMainQueue").invoke(null);addOperation = operationQueue.getDeclaredMethod("addOperation", Runnable.class);} catch (Exception e) {throw new AssertionError(e);}}@Override public void execute(Runnable r) {try {// queue.addOperation(r);addOperation.invoke(queue, r);} catch (IllegalArgumentException | IllegalAccessException e) {throw new AssertionError(e);} catch (InvocationTargetException e) {Throwable cause = e.getCause();if (cause instanceof RuntimeException) {throw (RuntimeException) cause;} else if (cause instanceof Error) {throw (Error) cause;}throw new RuntimeException(cause);}}}}
}

我们可以看到,如果检测到Android平台,会首先创建一个默认MainThreadExecutor的方法,(会在retrofit的build方法中调用,然后加到adapterFactories中),它会获取ui线程的looper生成一个对应的handler,执行execute方法就是用主线程的handler执行handler.post(runnable)事件,然后用这个MainThreadExector生成一个默认的ExecutorCallAdapterFactory。Retrofit 需要 Java7 版本或 Android2.3 以上。

在build方法中我们可以看到必须传入baseurl,当不指定client的时候为默认的okhttpclient,在Platform中生成的MainThreadExecutor是回调执行者,在子线程获得网络数据之后转换到ui线程中,CallAdapterFactory通过工厂模式生成CallAdapter用静态代理的方式将网络请求返回的call进行包装,比如RxJava,ConverterFactory通过工厂模式生成Converter对网络请求数据进行转化,比如Gson。最后通过建造者模式生成retrofit对象 把定义的接口转化为实例

CallAdapter是Call的适配器,作用就是创建/转换Call对象,把Call转换成预期的格式。CallAdatper创建是通过CallAdapter.factory工厂类进行的,本身只有一个转换方法adapt()。创建CallAdatper Factory需要实现Factory接口,DefaultCallAdapter为Retrofit2自带默认Call转换器,用来生成OKHTTP的call请求调用。

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, 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 serviceMethod = loadServiceMethod(method);OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);return serviceMethod.callAdapter.adapt(okHttpCall);}});}

可以看出我们采用动态代理的方式,返回了我们传入的接口的代理实例,并和InvocationHandler关联起来,当我们调用代理类的方法时,invoke方法都会被执行,
invoke方法中首先把method转化为servicemethod

  ServiceMethod loadServiceMethod(Method method) {ServiceMethod result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {result = new ServiceMethod.Builder(this, method).build();serviceMethodCache.put(method, result);}}return result;}

通过建造者模式将method构建为ServiceMethod,

 public Builder(Retrofit retrofit, Method method) {this.retrofit = retrofit;this.method = method;this.methodAnnotations = method.getAnnotations();this.parameterTypes = method.getGenericParameterTypes();this.parameterAnnotationsArray = method.getParameterAnnotations();}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);}

在build方法中,构建calladapter对象,

private CallAdapter<?> createCallAdapter() {Type returnType = method.getGenericReturnType();if (Utils.hasUnresolvableType(returnType)) {throw methodError("Method return type must not include a type variable or wildcard: %s", returnType);}if (returnType == void.class) {throw methodError("Service methods cannot return void.");}Annotation[] annotations = method.getAnnotations();try {return retrofit.callAdapter(returnType, annotations);} catch (RuntimeException e) { // Wide exception range because factories are user code.throw methodError(e, "Unable to create call adapter for %s", returnType);}}

通过得到method的类型和注解,调用retrofit.callAdapter(returnType, annotations)——nextCallAdapter方法中会通过for循环从adapterFactories中获取calladAdapter对象,这会得到一个ExecutorCallAdapter对象;同理我们类似的得到responseConverter对象,主要是对数据进行转化。除此之外还会对方法注解进行解析

private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} else if (annotation instanceof HEAD) {parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);if (!Void.class.equals(responseType)) {throw methodError("HEAD method must use Void as response type.");}} else if (annotation instanceof PATCH) {parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);} else if (annotation instanceof POST) {parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);} else if (annotation instanceof PUT) {parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);} else if (annotation instanceof OPTIONS) {parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);} else if (annotation instanceof HTTP) {HTTP http = (HTTP) annotation;parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());} else if (annotation instanceof retrofit2.http.Headers) {String[] headersToParse = ((retrofit2.http.Headers) annotation).value();if (headersToParse.length == 0) {throw methodError("@Headers annotation is empty.");}headers = parseHeaders(headersToParse);} else if (annotation instanceof Multipart) {if (isFormEncoded) {throw methodError("Only one encoding annotation is allowed.");}isMultipart = true;} else if (annotation instanceof FormUrlEncoded) {if (isMultipart) {throw methodError("Only one encoding annotation is allowed.");}isFormEncoded = true;}}

以及参数注解进行解析等。
得到ServiceMethod对象后,我们通过接口传入的参数来得到okhttpcall对象

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {this.serviceMethod = serviceMethod;this.args = args;}

然后就是把okhttpcall封装为call对象serviceMethod.callAdapter.adapt(okHttpCall)serviceMethod.callAdapter就是之前提到的ExecutorCallAdapterFactory生成的CallAdapter,在它的adapt方法中

public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {if (getRawType(returnType) != Call.class) {return null;}final Type responseType = Utils.getCallResponseType(returnType);return new CallAdapter<Call<?>>() {@Override public Type responseType() {return responseType;}@Override public <R> Call<R> adapt(Call<R> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);}};}

adapt方法会返回一个ExecutorCallBackCall对象,callbackExecutor就是我们在检测platform时创建的MainThreadExector,
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
,call是我们刚过传入的okhttpcall。
综上就是动态代理的作用,看上去是调用了接口的 方法,其实此时Retrofit把 接口翻译成一个HTTP请求,这个请求中有callAdapter,responseAdapter,okhttpcall三个重要的对象。我们得到接口的代理实例后,调用请求会触发InvocationHandler的invoke方法,并返回一个ExecutorCallBackCall对象,并把okhttpcall传入它的参数中,通过这个call对象完成我们的请求。有两种请求方式,execute和enqueue;

 异步请求enqueue中
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) {if (callback == null) throw new NullPointerException("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);}}});}

这里有两个对象,一个是callbackexecutor,一个是delegate,前者把网络线程切换到主线程中(我们在retrofit的build方法中检测platform时执行的),后者执行真正的网络请求(就是我们之前传入的callback对象)

@Override public void enqueue(final Callback<T> callback) {if (callback == null) throw new NullPointerException("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();}}});}

在okhttpcall的enque对象中我们直接调用的okhttp进行的网络异步操作;类似的okhttpcall也是应用okhttp进行的同步请求。关于okhttp在这里就不详述了,有兴趣的可以看下 深入解析OkHttp3

注意无论是同步操作还是异步操作每一个call对象实例只能被执行一次,多次执行抛出异常。并且我们通过Clone方法创建一个一模一样的实例,并且它的开销也是很小的。

下面是retrofit与另一款常用的volley库的简单对比:

Volley:
1.缓存处理;Volley自己就提供了一套完整的缓存处理方案,默认使用文件存储到磁盘中
2.代码简单,可读性高。
3.同一个请求如果同时都在发送,那么实际上只会有一个请求真正发出去, 其它的请求会等待这个结果回来
4.请求发送的时候提供了优先级的概念,但是是只保证顺序出去,不保证顺序回来
5.支持不同的Http客户端实现,默认提供了HttpClient和HttpUrlConnection的实现,而Retrofit在2.0版本之后,锁死在OkHttp上了。
6.支持请求取消
Retrofit:
1.较好的可扩展性,Volley中每一个新建一个Request时都需要指定一个父类,告知序列化数据的方式,而Retrofit中只需要在配置时,指定各种转换器即可。CallAdapter的存在,可以使你随意代理调用的Call
2.OkHttpClient自带并发光环,而Volley中的工作线程是自己维护的,那么就有可能存在线程由于异常退出之后,没有下一个工作线程补充的风险(线程池可以弥补这个缺陷),这在Retrofit中不存在
3.支持请求取消
4.Retrofit没有对缓存提供任何额外支持,缓存不在我们的控制范围之内,而是完全通过OkHttp来管理