美文网首页
从使用过程分析Retrofit的执行流程

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

作者: Camellia666 | 来源:发表于2021-08-06 18:03 被阅读0次

    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的大体执行流程,其中忽略了很多细节,希望对你能有帮助。

    相关文章

      网友评论

          本文标题:从使用过程分析Retrofit的执行流程

          本文链接:https://www.haomeiwen.com/subject/galivltx.html