Retrofit2源码解析——网络调用流程(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

Retrofit2源码解析系列

本文基于Retrofit2的2.4.0版本

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

网络调用流程分析

我们在发起异步网络请求时是这样调用的:

MyService myService = retrofit.create(MyService.class);
Call<IpBean> call = myService.getData();
call.enqueue(new Callback<IpBean>() {
    @Override
    public void onResponse(Call<IpBean> call, Response<IpBean> response) {
        
    }

    @Override
    public void onFailure(Call<IpBean> call, Throwable t) {
        
    }
});

总结起来就是三步:通过create方法生成我们的接口对象、调用接口得到Call、调用Call发起网络请求。我们分别来看看这三步Retrofit2都干了些啥。

创建接口对象

//Retrofit.class
public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
            new InvocationHandler() {
                private final Platform platform = Platform.get();

                @Override
                public 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);
                    }
                    //这里默认返回是false,所以不会执行
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    //创建serviceMethod
                    ServiceMethod<Object, Object> serviceMethod =
                            (ServiceMethod<Object, Object>) loadServiceMethod(method);
                    //创建OkHttpCall,用于进行网络请求
                    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    //返回经过适配器适配后的okHttpCall
                    return serviceMethod.adapt(okHttpCall);
                }
            });
}

可以看到Retrofit的create方法返回的是一个动态代理对象,当我们调用通过create方法生成的接口对象myService时,就会调用代理对象的invoke方法。在invoke方法中做了几件事:

(1)根据调用的具体方法Method(比如我们调用的getData方法),生成ServiceMethod

(2)用生成的ServiceMethod和方法中的参数生成OkHttpCall用于后面调用OkHttp3请求网络

(3)将生成的OkHttpCall通过Call适配器适配以后返回,也就是将OkHttpCall转换成需要的Call类型,比如Retrofit2的Call,RxJava的Observable等,供我们调用。

调用接口得到Call

我们调用接口myService的getData方法时,会调用上面提到的动态代理对象的invoke方法,invoke方法会分别创建ServiceMethod、OkHttpCall,并将OkHttpCall适配返回我们需要的Call对象。下面我们来深入源码看看Retrofit是怎么做这些事儿的。

(1)首先我们看看是怎么创建ServiceMethod的。

//Retrofit.class
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}

Retrofit中利用ConcurrentHashMap对ServiceMethod进行了缓存,创建ServiceMethod时会先去缓存中找,缓存中没有的话再调用ServiceMethod的Builder创建。因为Retrofit会为我们写的接口类中的每一个方法都创建一个ServiceMethod,所以ServiceMethod的数量会很多,利用缓存可以提高效率。

public ServiceMethod build() {
    //找到该方法所需要的CallAdapter
    callAdapter = createCallAdapter();
    responseType = callAdapter.responseType();
    ...
    //找到该方法需要的返回类型转换器
    responseConverter = createResponseConverter();
    
    //解析方法中的注解
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }

    ...
    //这里省略解析参数中的注解步骤
    ...

    return new ServiceMethod<>(this);
}

ServiceMethod的build方法中除了解析方法和参数的注解,最重要的就是确定该方法(每一个方法对应一个ServiceMethod)的CallAdapter和ResponseConverter。我们在构建Retrofit时可以添加多个CallAdapter和ResponseConverter,而这些CallAdapter和ResponseConverter都存放在Retrofit的对应的列表中,所以这里肯定需要去Retrofit的列表里找,我们来看看。

//ServiceMethod.class
private CallAdapter<T, R> createCallAdapter() {
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
    }
    Annotation[] annotations = method.getAnnotations();
    try {
        
        //通过retrofit的callAdapter方法来查找对应的CallAdapter
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
    }
}

可以看到这里确实是通过retrofit来查找CallAdapter的,那我们去Retrofit的callAdapter方法方法看看

//Retrofit.class
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
                                         Annotation[] annotations) {
    ...

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }

    ...
}

callAdapter方法中会遍历callAdapterFactories列表中的CallAdapterFactory,并调用其get方法,尝试获取CallAdapter,如果CallAdapter不为null,就说明是要找的CallAdapter。这里我们来简单看下默认的CallAdapterFactory的get方法。

从本文的开头的分析我们知道,默认的CallAdapterFactory是Platform的内部类Android返回的ExecutorCallAdapterFactory

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    ...
    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        ...
    }
    
    ...
}

可以看到,ExecutorCallAdapterFactory的get方法首先会判断当前的返回类型是不是Call以及Call的子类,不是的话就返回null。所以这就是Retrofit从适配器列表中找到对应适配器的方法依据。比如我们再来看看RxJava的适配器:

//RxJavaCallAdapterFactory.class
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
    ...
    if (rawType != Observable.class && !isSingle && !isCompletable) {
      return null;
    }

    ...

    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
}

所以当我们接口需要的是Observable时,我们就需要给Retrofit设置RxJava的适配器,这样Retrofit在创建ServiceMethod时就能找到对应的RxJava适配器了。

(2)创建OkHttpCall

创建OkHttpCall比较简单,直接调用构造方法就行

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}

(3)返回接口需要的Call对象

从上面的分析中我们知道,是通过serviceMethod的adapt方法来返回目标Call对象的,那我们来看看serviceMethod的adapt方法

T adapt(Call<R> call) {
    return callAdapter.adapt(call);
}

可以看到调用的serviceMethod中的callAdapter的adapt方法,也就是在上面的创建ServiceMethod的过程中确定的CallAdapter的adapt方法。这里我们看看默认的CallAdapter的adapt方法,也就是ExecutorCallAdapterFactory的adapt方法

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {

    ...
    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }

            @Override
            public Call<Object> adapt(Call<Object> call) {
                return new ExecutorCallbackCall<>(callbackExecutor, call);
            }
        };
    }
    
    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) {
            checkNotNull(callback, "callback == null");

            delegate.enqueue(new Callback<T>() {
                @Override
                public void onResponse(Call<T> call, final Response<T> response) {
                    callbackExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            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(new Runnable() {
                        @Override
                        public void run() {
                            callback.onFailure(ExecutorCallbackCall.this, t);
                        }
                    });
                }
            });
        }

        @Override
        public Response<T> execute() throws IOException {
            return delegate.execute();
        }

        ...
    }
}

可以看到,ExecutorCallAdapterFactory的adapt方法返回的是ExecutorCallAdapterFactory的内部类ExecutorCallbackCall,ExecutorCallbackCall内部有2部分组成,一个是回调执行器callbackExecutor,这个是用于将请求结果回调到主线程的;另一是Call对象,这里对应的就是OkHttpCall,因为我们调用adapt方法传入的就是OkHttpCall。

所以到这里其实网络调用的前半部分流程就清楚了:

我们在调用我们的接口方法myService的getData方法时,实际上调用的是Retrofit为我们生成的代理类的invoke方法,invoke方法会创建ServiceMethod和OkHttpCall,ServiceMethod中保存着对应CallAdapter和ResponseConverter,然后会调用ServiceMethod中的adapt方法利用CallAdapter将OkHttpCall转换成我们需要的Call类型并返回给我们调用。当我们调用Call进行网络请求时实际上调用的就是OkHttpCall对应的方法。

下篇文章我们再来分析下网络调用的下半部分流程,也就是Retrofit是怎么将OkHttp3请求返回的Response转换成我们实际需要的类型的?


欢迎关注我的微信公众号,和我一起每天进步一点点!
AntDream

目录
相关文章
|
15天前
|
监控 安全 开发工具
鸿蒙HarmonyOS应用开发 | HarmonyOS Next-从应用开发到上架全流程解析
HarmonyOS Next是华为推出的最新版本鸿蒙操作系统,强调多设备协同和分布式技术,提供丰富的开发工具和API接口。本文详细解析了从应用开发到上架的全流程,包括环境搭建、应用设计与开发、多设备适配、测试调试、应用上架及推广等环节,并介绍了鸿蒙原生应用开发者激励计划,帮助开发者更好地融入鸿蒙生态。通过DevEco Studio集成开发环境和华为提供的多种支持工具,开发者可以轻松创建并发布高质量的鸿蒙应用,享受技术和市场推广的双重支持。
202 11
|
12天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
12天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
12天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
14天前
|
网络协议
TCP报文格式全解析:网络小白变高手的必读指南
本文深入解析TCP报文格式,涵盖源端口、目的端口、序号、确认序号、首部长度、标志字段、窗口大小、检验和、紧急指针及选项字段。每个字段的作用和意义详尽说明,帮助理解TCP协议如何确保可靠的数据传输,是互联网通信的基石。通过学习这些内容,读者可以更好地掌握TCP的工作原理及其在网络中的应用。
|
13天前
|
存储 监控 网络协议
一次读懂网络分层:应用层到物理层全解析
网络模型分为五层结构,从应用层到物理层逐层解析。应用层提供HTTP、SMTP、DNS等常见协议;传输层通过TCP和UDP确保数据可靠或高效传输;网络层利用IP和路由器实现跨网数据包路由;数据链路层通过MAC地址管理局域网设备;物理层负责比特流的物理传输。各层协同工作,使网络通信得以实现。
|
14天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
62 1
|
19天前
|
域名解析 弹性计算 安全
阿里云服务器租用、注册域名、备案及域名解析完整流程参考(图文教程)
对于很多初次建站的用户来说,选购云服务器和注册应及备案和域名解析步骤必须了解的,目前轻量云服务器2核2G68元一年,2核4G4M服务器298元一年,域名注册方面,阿里云推出域名1元购买活动,新用户注册com和cn域名2年首年仅需0元,xyz和top等域名首年仅需1元。对于建站的用户来说,购买完云服务器并注册好域名之后,下一步还需要操作备案和域名绑定。本文为大家展示阿里云服务器的购买流程,域名注册、绑定以及备案的完整流程,全文以图文教程形式为大家展示具体细节及注意事项,以供新手用户参考。
|
13天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
20天前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
59 17

热门文章

最新文章