Retrofit通过OkHttp发送请求的过程
Posted datian1234
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit通过OkHttp发送请求的过程相关的知识,希望对你有一定的参考价值。
retrofit是对okhttp的封装。retrofit使用注解来创建请求的,retrofit的注解有哪些,分别代表什么意义,有大量的博客都有介绍,我就不重复了。但注解创建的请求,很显然是不能被okhttp识别的,其中必定有个转换的过程。这个过程我没有搜到,所以我阅读了retrofig源码,把用注解创建的请求,变为okhttp请求的过程梳理了出来。这篇博客是分析retrofit如何生成请求,如何转换为okhttp的请求并发送出去的过程。
源码分析基于com.squareup.retrofit2:retrofit:2.9.0
Retrofit的使用实例
Retrofit retrofit = new Retrofit.Builder().baseUrl("<https://api.uomg.com/>")
.addConverterFactory(GsonConverterFactory.create())
.build();
ICity iCity = retrofit.create(ICity.class);
Call cityCall = iCity.aa("<https://node.kg.qq.com/play?s=YaCv8EYfJunVWYcH>"); // 这里url是个请求参数
cityCall.enqueue(Callback);
public interface ICity
@GET("api/get.kg")
Call aa(@Query("songurl") String str);
@FormUrlEncoded
@POST("api/get.kg")
Call post(@Field("songurl") String str);
创建请求类的对象的过程,使用了动态代理
retrofit.create()只是创建ICity的动态代理,只有在执行iCity.aa()时,里面的InvocationHandler.invoke()才会执行。 ICity中,每一个方法都是一个请求,ICity是把这些请求封装到一个类。
- Retrofit.java
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);
);
private void validateServiceInterface(Class<?> service)
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods())
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers()))
loadServiceMethod(method);
当iCity.aa()执行时,InvocationHandler.invoke()会被执行。别问为啥,动态代理就是这么干的。
invoke()的三个入参中,Object proxy, Method method, @Nullable Object[] args,Object proxy是ICity的代理对象(细说我就不知道了);Method method是java反射中的Method,由于前面执行的是aa()方法,所以这里就是这个方法;Object[] args是aa()方法的入参。
method.getDeclaringClass()返回的是ICity,isDefaultMethod()条件:public、非抽象、非静态,所以会走loadServiceMethod(method).invoke(args)。
loadServiceMethod(method).invoke(args),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;
下面来看ServiceMethod的生成过程。
- ServiceMethod.java
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
核心部分在HttpServiceMethod.parseAnnotations()中
- HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
/* 对kotlin支持 */
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction)
else
adapterType = method.getGenericReturnType();
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction)
// 疑问一、要求返回ServiceMethod,为什么返回CallAdapted
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 注意CallAdapted与前面CallAdapter,消息看错成一个类
疑问一、要求返回ServiceMethod,为什么返回CallAdapted
肯定有继承关系。具体是CallAdapted 继承于 HttpServiceMethod,HttpServiceMethod又是ServiceMethod的实现。
class CallAdapted extends HttpServiceMethod
private final CallAdapter callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter responseConverter,
CallAdapter callAdapter)
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
HttpServiceMethod
private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final Converter responseConverter;
loadServiceMethod(method).invoke(args),invoke部分
入口在HttpServiceMethod.invoke
final @Nullable ReturnT invoke(Object[] args)
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
这里的Call、OkHttpCall都是Retorfit自定义的类,他们在retrofit2包中,不是OkHttp的。OkHttpCall把RequestFactory、入参、callFactory、responseConverter封装起来而已。
先不管这些入参怎么来的。HttpServiceMethod类中,adapt是抽象方法,前面的loadServiceMethod()实际返回的是CallAdapted对象,所以adapt也应该看CallAdapted的。
- CallAdapted是内部类,HttpServiceMethod$CallAdapted.java
protected ReturnT adapt(Call call, Object[] args)
return callAdapter.adapt(call);
要找到callAdapter是怎么创建的,找到这个对象的类,才能找到实现。callAdapter对象的创建,由loadServiceMethod()启动,过程在HttpServiceMethod.parseAnnotations()中,
- HttpServiceMethod.java
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); // 不要把CallAdapter和后面的CallAdapted混淆
if (!isKotlinSuspendFunction)
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
这一句 CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); 依次调用关系:createCallAdapter 》 retrofit.callAdapter 》 nextCallAdapter,最后到
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations)
for (int i = start, count = callAdapterFactories.size(); i < count; i++)
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null)
return adapter;
这里callAdapterFactories.get(i)得到的应该是应该是Platform.defaultCallAdapterFactories()内创建的DefaultCallAdapterFactory对象,看起get()方法,这是创建CallAdapter的方法。
- DefaultCallAdapterFactory.java
public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit)
if (getRawType(returnType) != Call.class)
return null;
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);
;
所以上面的callAdapter,是在这儿创建的new CallAdapter()。 前面还提到的的callAdapter.adapt(),应该走到这儿来;由CallAdapter生产的Call,就是这里的ExecutorCallbackCall。判断条件分析略过。 可以看到ExecutorCallbackCall跟Call是存在继承关系的。 注意new ExecutorCallbackCall<>(executor, call)有一个入参call,ExecutorCallbackCall里面其实还是调用这个入参完成的,ExecutorCallbackCall只是充当一个代理,或者适配器的作用,真正还是参数call,即OkHttpCall。
- ExecutorCallbackCall是内部类,详见DefaultCallAdapterFactory$ExecutorCallbackCall.java
class ExecutorCallbackCall<T> implements Call<T>
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) // 入参call
this.delegate = delegate;
@Override
public void enqueue(final Callback<T> callback)
delegate.enqueue(Callback);
请求的发送流程。Call.enqueue()
前面Retrofit使用实例中,cityCall.enqueue,是Retrofit中的Call入列。这个Call是OkHttpCall,我们要看Retrofit的Call怎么转换为OkHttp的Call,并如入列。
- OkHttpCall.java
public void enqueue(final Callback<T> callback)
okhttp3.Call call;
call = rawCall = createRawCall();
call.enqueue();
private okhttp3.Call createRawCall() throws IOException
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
是通过这一句callFactory.newCall(requestFactory.create(args))创建的OkHttp的Call,有三个问题,1、callFactory(是okhttp3.Call.Factory)怎么创建的;2、RequestFactory的创建过程;3、RequestFactory创建OkHttp的Request的过程。
1、callFactory(是okhttp3.Call.Factory)怎么创建的
callFactory是okhttp中的类,用来生成okhttp中的call。下面是callFactory在retrofit各环节中的使用流程。
1、Retrofit是用建造者模式创建的,callFactory在这里被创建,并保存为Retrofit类的成员变量。
- Retrofit.java
build()
callFactory = new OkHttpClient();
new Retrofit(callFactory...);
2、在HttpServiceMethod.parseAnnotations()中,从retrofit中获取callFactory,并通过构造方法传递给CallAdapted。
- HttpServiceMethod.java
static ... parseAnnotations()
okhttp3.Call.Factory callFactory = retrofit.callFactory;
new CallAdapted<>(callFactory...);
3、callFactory传递给CallAdapted后,在经由父类传递给retrofit2.Call。
- HttpServiceMethod.java
private final okhttp3.Call.Factory callFactory;
HttpServiceMethod(...okhttp3.Call.Factory callFactory)
this.callFactory = callFactory;
/* callFactory是HttpServiceMethod的成员变量,由外部通过构造方法传入 */
final @Nullable ReturnT invoke(Object[] args)
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
4、callFactory创建okhttp中的Call的过程。
承上,callFactory被封装到retrofit2.Call之后,HttpServiceMethod类调用adapter()方法,实际走到CallAdapted.adapter();
protected ReturnT adapt(Call<ResponseT> call, Object[] args)
return callAdapter.adapt(call);
前面介绍过,callAdapter.adapt()生成的Call只是代理(适配器),真正的Call对象还是这个入参Call。他的真实面目在HttpServiceMethod.invoke()中
final @Nullable ReturnT invoke(Object[] args)
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
这里就把callFactory传递给了Call对象。在Call.enqueue()中,用这个callFactory生成okhttp的Call。
- OkHttpCall.java
enquque()
createRawCall();
private okhttp3.Call createRawCall() throws IOException
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
2、RequestFactory的创建过程;
Retrofit.loadServiceMethod()调用ServiceMethod.parseAnnotations();
- ServiceMethod.java
static ... parseAnnotations(Retrofit retrofit, Method method)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
深入RequestFactory.parseAnnotation,看RequestFactory的创建过程,及重要的参数。
- RequestFactory.java
RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method)
return new Builder(retrofit, method).build();
RequestFactory(Builder builder)
method = builder.method; // java.lang.reflect.Method,对应一个请求接口,对应一个RequestFactory
baseUrl = builder.retrofit.baseUrl; // 域名
httpMethod = builder.httpMethod; // get、post
relativeUrl = builder.relativeUrl; // 网关,解析接口的注解得到,详见RequestFactory.parseHttpMethodAndPath(),根源于method.getAnnotations()
parameterHandlers = builder.parameterHandlers; // 请求参数
...
/** 建造者是内部类 */
class Builder {
Annotation[] methodAnnotations;
Annotation[][] parameterAnnotationsArray;
Builder()
this.methodAnnotations = method.getAnnotations(); // 获取接口方法的注解
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations(); // 获取接口方法的形式参数的注解
RequestFactory build()
for (Annotation annotation : methodAnnotations)
/* 获取get|post请求方式,获取网关 */
parseMethodAnnotation(annotation);
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++)
/* 解析接口方法的参数注解,是请求参数的key、value对应 */
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
return new RequestFactory(this);
}
}
3、RequestFactory创建OkHttp的Request的过程
OkHttpCall.createRawCall()中,okhttp3.Call call = callFactory.newCall(requestFactory.create(args)),callFactory.newCall的入参是okhttp中的Request,requestFactory.create就是返回一个okhttp3.Request。
- RequestFactory.java
ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl...);
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
其中requestBuilder.get()是将请求的进一步处理,如全url,符合RequestBody格式的参数等。build()创建Request对象。
以上是关于Retrofit通过OkHttp发送请求的过程的主要内容,如果未能解决你的问题,请参考以下文章
带你一步步剖析Retrofit 源码解析:一款基于 OkHttp 实现的网络请求框架
Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架