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 实现的网络请求框架

面试系列——Retrofit 框架分析使用总结

retrofit和okhttp请求url的参数拼接

Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架

Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架

Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架