Retrofit2源码解析
到了最后一个环节,就是底层原理,是什么样的底层原理和源码支撑Retrofit2的功能?这部分就来一探究竟。首先来看下retrofit如何对接口进行代理对象创建,这个其实是retrofit的核心,也就是创建动态代理对象,以上内容分为两步:
public T getRetrofit(String baseUrl, Class<T> proxy) { Retrofit retrofit = new Retrofit.Builder().client(okHttpClient).baseUrl(baseUrl) .addConverterFactory(JacksonConverterFactory.create(JsonUtils.getObjectMapper())).build(); return retrofit.create(proxy); }
1 构建Retrofit对象
构建的大致源码如下,相当于对Retrofit进行一些基础设施的配置:
public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private @Nullable HttpUrl baseUrl; private final List<Converter.Factory> converterFactories = new ArrayList<>(); private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; Builder(Platform platform) { this.platform = platform; } public Builder() { this(Platform.get()); } /** * The HTTP client used for requests. * * <p>This is a convenience method for calling {@link #callFactory}. */ public Builder client(OkHttpClient client) { return callFactory(Objects.requireNonNull(client, "client == null")); } /** * Specify a custom call factory for creating {@link Call} instances. * * <p>Note: Calling {@link #client} automatically sets this value. */ public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = Objects.requireNonNull(factory, "factory == null"); return this; } /** * Set the API base URL. * * @see #baseUrl(HttpUrl) */ public Builder baseUrl(String baseUrl) { Objects.requireNonNull(baseUrl, "baseUrl == null"); return baseUrl(HttpUrl.get(baseUrl)); } /** Add converter factory for serialization and deserialization of objects. */ public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this; } /** * Add a call adapter factory for supporting service method return types other than {@link * Call}. */ public Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this; } /** * The executor on which {@link Callback} methods are invoked when returning {@link Call} from * your service method. * * <p>Note: {@code executor} is not used for {@linkplain #addCallAdapterFactory custom method * return types}. */ public Builder callbackExecutor(Executor executor) { this.callbackExecutor = Objects.requireNonNull(executor, "executor == null"); return this; } /** Returns a modifiable list of call adapter factories. */ public List<CallAdapter.Factory> callAdapterFactories() { return this.callAdapterFactories; } /** Returns a modifiable list of converter factories. */ public List<Converter.Factory> converterFactories() { return this.converterFactories; } /** * When calling {@link #create} on the resulting {@link Retrofit} instance, eagerly validate the * configuration of all methods in the supplied interface. */ public Builder validateEagerly(boolean validateEagerly) { this.validateEagerly = validateEagerly; return this; } }
- baseUrl必须指定,这个是理所当然的,设定访问地址的域名
- 如果不设置callFactory,则默认直接
new OkHttpClient()
,如果需要对OkHttpClient
进行详细的设置,需要构建OkHttpClient对象,然后传入 - callbackExecutor是用来将回调传递到UI线程,当然这里设计的比较巧妙,利用platform对象,对平台进行判断,判断主要是利用
Class.forName("")
进行查找,如果是Android平台,会自定义一个Executor对象,并且利用Looper.getMainLooper()实例化一个handler对象,在Executor内部通过handler.post(runnable)
- adapterFactories主要用于对Call进行转化,基本上不需要我们自己去自定义
- converterFactories用于转化数据,例如将返回的responseBody转化为对象等;当然不仅仅是针对返回的数据,还能用于一般备注解的参数的转化例如
@Body
标识的对象做一些操作
以上就是几个基础设施参数。
2 创建代理对象
什么是动态代理呢,其实之前在学习MyBaits和Spring的AOP机制的时候都了解过,这里不再赘述,把我的这两篇Blog贴到这里:【MyBatis学习笔记 四】MyBatis基本运行原理源码解析,以及【Spring学习笔记 六】静态/动态代理实现机制。说白了动态代理就是接口方法的拦截者,在方法执行时增加额外逻辑,而Retrofit2的代理和MyBatis有异曲同工之妙,就是都没有具体的实现类,单纯的进行代理实现。
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); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); }
1 loadServiceMethod方法
loadServiceMethod方法用来构建一个ServiceMethod对象:
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; }
这里调用了parseAnnotations方法进行注解解析
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); }
我们看到这里调用了HttpServiceMethod.parseAnnotations
,整个过程就是在其中进行了注解的解析,整体代码如下:
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); Type adapterType; if (isKotlinSuspendFunction) { Type[] parameterTypes = method.getGenericParameterTypes(); Type responseType = Utils.getParameterLowerBound( 0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]); if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) { // Unwrap the actual body type from Response<T>. responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType); continuationWantsResponse = true; } else { // TODO figure out if type is nullable or not // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class) // Find the entry for method // Determine if return type is nullable or not } adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType); annotations = SkipCallbackExecutorImpl.ensurePresent(annotations); } else { adapterType = method.getGenericReturnType(); } CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); if (responseType == okhttp3.Response.class) { throw methodError( method, "'" + getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } if (responseType == Response.class) { throw methodError(method, "Response must include generic type (e.g., Response<String>)"); } // TODO support Unit for Kotlin? if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) { throw methodError(method, "HEAD method must use Void as response type."); } Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } }
以上整个部分就是就行了ServiceMethod对象的构建,而serviceMethod的调用如下:
2 invoke方法获取call对象
@Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); }
再向下跟看一下adapt方法做了什么:
3 装饰者模式获取具体接口方法代理对象
final class DefaultCallAdapterFactory extends CallAdapter.Factory { private final @Nullable Executor callbackExecutor; DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) { this.callbackExecutor = callbackExecutor; } @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); } }; }
可以看到我们已经确定这个adapt方法返回是:ExecutorCallAdapterFactory.get()
对应代码为:
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) { Objects.requireNonNull(callback, "callback == null"); delegate.enqueue( new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute( () -> { 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(() -> 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(); } @Override public Timeout timeout() { return delegate.timeout(); } } }
可以看出ExecutorCallbackCall仅仅是对Call对象进行封装,类似装饰者模式,只不过将其执行时的回调通过callbackExecutor进行回调到UI线程中去了
3 执行Call调用的方法
我们已经拿到了经过封装的ExecutorCallbackCall类型的call对象,实际上就是我们实际在写代码时拿到的call对象,那么我们一般会执行execute方法,看看源码是怎么做的
@Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = getRawCall(); } if (canceled) { call.cancel(); } return parseResponse(call.execute()); }
可以看到执行层面还是依赖okhttp3的。
综合以上可以看到我们通过Proxy.newProxyInstance产生的代理类,当调用接口的任何方法时,都会调用InvocationHandler#invoke
方法,在这个方法中可以拿到传入的参数,注解等。retrofit也可以通过同样的方式,在invoke方法里面,拿到所有的参数,注解信息然后就可以去构造RequestBody,再去构建Request,得到Call对象封装后返回。
总结一下
Retrofit2其实是一个非常好的优化体验的框架,其核心还是调用OkHttp框架进行网络接口请求,其最大的好处就是让我们调用网络接口就像调用普通接口一样方便,通过各种注解方便的进行网络请求。通过源码的学习知道了其其实是通过动态代理实现的,动态代理还帮我们搞定了MyBatis框架、AOP,可见知道一种技术原理其收益远大于知道一种简单的框架使用,而一种技术原理又来自于一种技术思想,由此可推,知道一种技术思想>知道一种技术原理>知道一种框架使用。