从使用过程分析Retrofit的执行流程

retrofit在业内已经被吹上天了,也基本上是面试必问的框架。它有什么优点,使用了哪些设计模式,网上很多,就不多说了,这里只用最简单的方式从retrofit的使用过程看一下retorfit的执行流程。

PS:本人是钢铁直男一枚,不喜欢用一些华丽的词藻,更不喜欢说一些废话,抓住核心要点,防止把大家搞的云里雾里,不知所云。

一,使用

首先看一下它的使用:

1,创建接口
public interface ApiService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}
2,使用
// 1,创建retrofit
val retrofit = Retrofit.Builder().baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    
// 2,创建代理对象
val service = retrofit.create(ApiService::class.java)

// 3,调用请求方法
val repos = service.listRepos("octocat")

// 4,发起请求并获取回调
repos.enqueue(object : Callback<List<Repo>> {
    override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
        LogUtil.e("result: " + response.body())
    }

    override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
        LogUtil.e("onFailure: " + t.toString())
    }
})

二,分析

根据上面使用的过程,分四个步骤分析retrofit的执行过程

1,创建retorfit

val retrofit = Retrofit.Builder().baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
//        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()

通过Builder模式创建retorfit,只需要查看其build()即可知道他都做了什么:

// 以下代码做了精简,知道是干啥的就行
public Retrofit build() {
    // 1, baseUrl
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }
    // 2, callFactory(也就是OkHttpClient)
    okhttp3.Call.Factory callFactory = new OkHttpClient();
    
    // 3, Executor(用于线程切换)
    Executor callbackExecutor = platform.defaultCallbackExecutor();

    // 4, callAdapterFactories(对请求的中间过程进行适配的工厂)
    // Make a defensive copy of the adapters and add the default Call adapter.
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);

    // 5, 结果转换器工厂
    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories = new ArrayList<>();
    ...
    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

retofit主要就包含了这5个对象,它们在后面都会用到。

2,创建代理对象

val service = retrofit.create(ApiService::class.java)

retofit的核心思想是动态代理,调用retofit的create(),并把ApiService接口作为参数就创建了一个代理对象。那么create()中都做了什么,代码如下:

// 简要代码
public <T> T create(final Class<T> service) {
    // 返回代理对象
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
            ...
        });
}

可以看到retrofit返回了一个对ApiService代理的对象。

注意:这里仅仅是创建了一个对象,InvocationHandler中的invoke()还没有开始执行。

3,调用请求方法

val repos = service.listRepos("octocat")

通过调用第二步创建的代理对象的方法就会获取一个可以发起请求的对象,它到底是一个什么对象,又是如何获取的呢?

首先你要了解动态代理,当调用listRepos("octocat")时才会执行第二步代理对象的InvocationHandlerinvoke()方法:

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 {
        ...
        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
    }
});

invoke()中的方法中的代码很简单,但其流程确实整个过程最复杂、最关键的。这里可以分为两步:

3.1,loadServiceMethod(method)

这一步获取了一个ServiceMethod对象,具体流程如下:

3.1.1 检查缓存

首先查看有没有缓存,没有的话就直接创建:

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;
}
3.1.2 直接创建
// 这里对源码做了适当调整的简化
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
  Retrofit retrofit, Method method) {
    // 1, 获取RequestFactory对象,它是对网络请求参数的封装,并且可以将这些参数转为OkHttp的请求参数
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    
    Annotation[] annotations = method.getAnnotations();
    Type adapterType = method.getGenericReturnType();
    // 2, callAdapter,对请求中间过程进行适配
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    ...
    // 3,对请求返回结果进行格式转换
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    // 4,callFactory也就是前面说到的OkHttpClient
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    // 5,创建CallAdapted
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}

在创建的过程中首先获取了四个重要对象:requestFactory,callAdapter,responseConverter,callFactory。然后通过这四个对象创建了一个CallAdapted对象:

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
        super(requestFactory, callFactory, responseConverter);
        this.callAdapter = callAdapter;
    }

    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
    }
}

可见它继承自HttpServiceMethod,也间接继承自ServiceMethod,这个CallAdapted对象也就是loadServiceMethod(method)的结果。

3.2,invoke(args != null ? args : emptyArgs)

上一步获取了一个ServiceMethod对象,接着看看ServiceMethodinvoke()

@Override 
final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}

该方法中首先创建了一个OkHttpCall,然后调用了adapt()方法,执行的就是也就是前CallAdapted对象的方法:

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;
    // 执行这个方法
    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
    }
}

可见调用adapt()方法返回的是callAdapter.adapt(call)的结果,那么这个callAdapter是什么?它是在前面3.1.2 小节中创建,这里不绕弯子了,它是直接new的一个CallAdapter对象,代码如下:

// DefaultCallAdapterFactory.java中
new CallAdapter<Object, Call<?>>() {
    public Type responseType() {
        return responseType;
    }
    // 执行这里
    public Call<Object> adapt(Call<Object> call) {
        return (Call)(executor == null ? call : new         DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
    }
};

因此调用adapt()方法最终返回的是一个DefaultCallAdapterFactory.ExecutorCallbackCall()对象。其简要代码如下:

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

    public void enqueue(final Callback<T> callback) {
        ...
    }
    ...
}   
3.3 小结
loadServiceMethod(method).invoke(args != null ? args : emptyArgs)

这一步执行了动态代理的过程,通过切面的方式给接口中的方法赋予了可以发起请求的能力。通过loadServiceMethod(method)获取了一个ServiceMethod对象,通过调用invoke()进行适配,获取了一个DefaultCallAdapterFactory.ExecutorCallbackCall对象。

4,发起请求并获取回调

repos.enqueue(object : Callback<List<Repo>> {
    override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
        LogUtil.e("result: " + response.body())
    }

    override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
        LogUtil.e("onFailure: " + t.toString())
    }
})

在第三步中获取了一个DefaultCallAdapterFactory.ExecutorCallbackCall对象,因此在调用上面enqueue()时调用的实际上是DefaultCallAdapterFactory.ExecutorCallbackCall中的enqueue(),接下来就看一下发起请求后最终如何通过OkHttp进行请求并返回结果。

4.1 ExecutorCallbackCall

DefaultCallAdapterFactory.ExecutorCallbackCall中的enqueue()如下:

// 简要代码
@Override 
public void enqueue(final Callback<T> callback) {
    delegate.enqueue(new Callback<T>() {
        @Override 
        public void onResponse(Call<T> call, final Response<T> response) {
            callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                    ...
                    callback.onResponse(ExecutorCallbackCall.this, response);
                }
            });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
            callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                    callback.onFailure(ExecutorCallbackCall.this, t);
                }
            });
        }
    });
}

它内部调用的是delegateenqueue()方法,将返回结果通过callbackExecutor来进行线程切换,并回调到业务层。

可见ExecutorCallbackCall是对delegate的包装,增加了切换线程的能力。

那么这里的delegate是什么?它是在3.2步中创建的OkHttpCall对象:

Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);

接下来看看OkHttpCall中的enqueue方法

4.2 OkHttpCall
// 简要代码
@Override 
public void enqueue(final Callback<T> callback) {
    ...
    okhttp3.Call call = createRawCall();
    ...

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
            // 返回结果格式转换
            response = parseResponse(rawResponse);
        } catch (Throwable e) {
            return;
        }

        try {
            callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }
      ...
    });
}

其中首先获取了一个okhttp3.Call,然后通过通过这个OkHttp的Call进行真正的网络请求,通过parseResponse()对请求结果进行转换,最终把结果回调到4.1ExecutorCallbackCall中。

可见OkHttpCall是对OkHttp的包装,增加了返回结果转换的能力。

4.3 小结

这里使用到了装饰器模式,ExecutorCallbackCall是对OkHttpCall的包装,增加了切换线程的能力;OkHttpCall是对OkHttp的包装,增加了返回结果转换的能力。

三,总结

retrofit的逻辑非常复杂,本文从使用者的使用过程分析了retrofit的大体执行流程,其中忽略了很多细节,希望对你能有帮助。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容