retrofit2.0源码分析 _学习笔记
本文篇幅较长,可以对应文章末尾的表格进行阅读
retrofit一般请求流程图解
创建retrofit实例
得到Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
//步骤1 new Retrofit
//步骤2.Builder
//步骤3baseUrl
//步骤4addConverterFactory
//步骤5build
Retrofit源码分析
<-- Retrofit类 -->
public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)
// 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
private final HttpUrl baseUrl;
// 网络请求的url地址
private final okhttp3.Call.Factory callFactory;
// 网络请求器的工厂
// 作用:生产网络请求器(Call)
// Retrofit是默认使用okhttp
private final List<CallAdapter.Factory> adapterFactories;
// 网络请求适配器工厂的集合
// 作用:放置网络请求适配器工厂
// 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
// 下面会详细说明
private final List<Converter.Factory> converterFactories;
// 数据转换器工厂的集合
// 作用:放置数据转换器工厂
// 数据转换器工厂作用:生产数据转换器(converter)
private final Executor callbackExecutor;
// 回调方法执行器
private final boolean validateEagerly;
// 标志位
// 作用:是否提前对业务接口中的注解进行验证转换的标志位
<-- Retrofit类的构造函数 -->
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories);
this.adapterFactories = unmodifiableList(adapterFactories);
// unmodifiableList(list)近似于UnmodifiableList<E>(list)
// 作用:创建的新对象能够对list数据进行访问,但不可通过该对象对list集合中的元素进行修改
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
...
// 仅贴出关键代码
}
成功建立一个Retrofit对象的标准,配置好Retrofit类里面的成员变量
- serviceMethod :包含所有的网络请求信息对象
- baseUrl 网络请求的url地址
- callFactory 网络请求工厂
- callFactories 网络请求适配器工厂的集合
- converterFactories :数据转换工厂的集合
- callbackExecutor 回执方法执行器
callAdapterFactory 是该Factory生产的是callAdapter
CallAdapter 详细介绍
定义网络请求执行器的适配器
- call 在retrofit中默认是okhttpcall
- Retrofit中提供4种callAdapterFactory: ExecutorCallAdapterFactory(默认),GuavaCallAdapterFactory,Java8CallAdapterFactory,RxjavaCallAdapterFactory
作用:将默认的网络请求器(OkhttpCall)转化为适合不同平台来调用的网络请求执行器形式.
Retrofit.Builder.addCallAdapterFactory(new RxjavaCallAdapterFactory().create()) 添加对Rxjava的支持
Builder类 (Retrofit.Builder)
<-- Builder类-->
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
// 从上面可以发现, Builder类的成员变量与Retrofit类的成员变量是对应的
// 所以Retrofit类的成员变量基本上是通过Builder类进行配置
// 开始看步骤1
<-- 步骤1 -->
// Builder的构造方法(无参)
public Builder() {
this(Platform.get());
// 用this调用自己的有参构造方法public Builder(Platform platform) ->>步骤5(看完步骤2、3、4再看)
// 并通过调用Platform.get()传入了Platform对象
// 继续看Platform.get()方法 ->>步骤2
// 记得最后继续看步骤5的Builder有参构造方法
}
...
}
<-- 步骤2 -->
class Platform {
private static final Platform PLATFORM = findPlatform();
// 将findPlatform()赋给静态变量
static Platform get() {
return PLATFORM;
// 返回静态变量PLATFORM,即findPlatform() ->>步骤3
}
<-- 步骤3 -->
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
// Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
if (Build.VERSION.SDK_INT != 0) {
return new Android();
// 此处表示:如果是Android平台,就创建并返回一个Android对象 ->>步骤4
}
} catch (ClassNotFoundException ignored) {
}
try {
// 支持Java平台
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
// 支持iOS平台
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
// 从上面看出:Retrofit2.0支持3个平台:Android平台、Java平台、IOS平台
// 最后返回一个Platform对象(指定了Android平台)给Builder的有参构造方法public Builder(Platform platform) --> 步骤5
// 说明Builder指定了运行平台为Android
return new Platform();
}
...
}
<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果
static class Android extends Platform {
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
// 创建默认的网络请求适配器工厂
// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
// 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
// 采用了策略模式
}
@Override
public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
// 获取与Android 主线程绑定的Handler
@Override
public void execute(Runnable r) {
handler.post(r);
// 该Handler是上面获取的与Android 主线程绑定的Handler
// 在UI线程进行对网络请求返回数据处理等操作。
}
}
// 切换线程的流程:
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
//2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程
}
// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
// Builder类的构造函数2(有参)
public Builder(Platform platform) {
// 接收Platform对象(Android平台)
this.platform = platform;
// 通过传入BuiltInConverters()对象配置数据转换器工厂(converterFactories)
// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器
converterFactories.add(new BuiltInConverters());
// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)
// new BuiltInConverters()是为了初始化数据转换器
}
总结Builder设置默认的
- 平台类型对象: Android
- 网络请求适配器: CalladapterFactory (CallAdapter对于原始的call进行再次封装,如call 到Observable)
- 数据转换工厂 : converterFactory
- 回调执行器 callbackExevutor
这里仅仅是设置了默认值,并没有配置给具体的retrofit类的成员变量中
BaseUrl源码分析
<-- 步骤1 -->
public Builder baseUrl(String baseUrl) {
// 把String类型的url参数转化为适合OKhttp的HttpUrl类型
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
// 最终返回带httpUrl类型参数的baseUrl()
// 下面继续看baseUrl(httpUrl) ->> 步骤2
return baseUrl(httpUrl);
}
<-- 步骤2 -->
public Builder baseUrl(HttpUrl baseUrl) {
//把URL参数分割成几个路径碎片
List<String> pathSegments = baseUrl.pathSegments();
// 检测最后一个碎片来检查URL参数是不是以"/"结尾
// 不是就抛出异常
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}总结
baseURL()用于适配Retrofit类的网络请求url地址(将传入的String类型url转化为适合OKhttp的HttpUrl类型的url)
GsonConverterFactory
- 先从GsonConverterFactory.creat()开始分析
public final class GsonConverterFactory extends Converter.Factory {
<-- 步骤1 -->
public static GsonConverterFactory create() {
// 创建一个Gson对象
return create(new Gson()); ->>步骤2
}
<-- 步骤2 -->
public static GsonConverterFactory create(Gson gson) {
// 创建了一个含有Gson对象实例的GsonConverterFactory
return new GsonConverterFactory(gson); ->>步骤3
}
private final Gson gson;
<-- 步骤3 -->
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
所以GsonConverterFactory.creat()是创建一个含有Gson对象的实例GsonConverterFactory并且返回给addConverterFactory
-
addConverterFactory();
// 将上面创建的GsonConverterFactory放入到 converterFactories数组 // 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(checkNotNull(factory, "factory == null")); return this; }
总结: 用于创建一个含有Gson对象的实例GsonConverterFactory并放入到数据转换器工厂converterFactories里
- 即retrofit默认使用的Gson进行解析
- 若想使用其他解析方式,也可以通过自定义数据解析器来完成(必须继承自coverter.Factory)
build源码分析
public Retrofit build() { <-- 配置网络请求执行器(callFactory)--> okhttp3.Call.Factory callFactory = this.callFactory; // 如果没指定,则默认使用okhttp // 所以Retrofit默认使用okhttp进行网络请求 if (callFactory == null) { callFactory = new OkHttpClient(); } <-- 配置回调方法执行器(callbackExecutor)--> Executor callbackExecutor = this.callbackExecutor; // 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor // 即Android默认的callbackExecutor if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } <-- 配置网络请求适配器工厂(CallAdapterFactory)--> List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); // 向该集合中添加了步骤2中创建的CallAdapter.Factory请求适配器(添加在集合器末尾) adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // 请求适配器工厂集合存储顺序:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂(ExecutorCallAdapterFactory) <-- 配置数据转换器工厂:converterFactory --> // 在步骤2中已经添加了内置的数据转换器BuiltInConverters()(添加到集合器的首位) // 在步骤4中又插入了一个Gson的转换器 - GsonConverterFactory(添加到集合器的首二位) List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); // 数据转换器工厂集合存储的是:默认数据转换器工厂( BuiltInConverters)、自定义1数据转换器工厂(GsonConverterFactory)、自定义2数据转换器工厂.... // 注: //1. 获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位-末位开始遍历 // 因此集合中的工厂位置越靠前就拥有越高的使用权限 // 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量 return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }
总结:
- 配置网络执行器
- 配置方法执行回调执行器
- 配置网络请求适配器工厂
- 配置数据转换工厂
把这4个变量配置给retrofit,创建Retrofit的实例.
对Retrofit总结
Retrofit使用建造者模式通过Builder类简历一个Retrofit实例,具体创建细节是配置了
- 平台类型对象(PlatForm-Android)
- 网络请求url地址(baseurl)
- 网络请求工厂(callFactory) 默认使用Okhttpcall
- 网络请求适配器工厂的集合(adapterFactories)本质是配置网络请求适配器工厂, 默认是ExecutorCallAdapterFactory
- 数据转换器工厂集合(converterFactories) 本质是配置了数据转换工厂
- 回调方法执行器(callbackExecutor)默认回调方法执行器的作用是切换线程
创建网络请求接口实例
使用步骤
<-- 步骤1:定义接收网络数据的类 -->
<-- JavaBean.java -->
public class JavaBean {
.. // 这里就不介绍了
}
<-- 步骤2:定义网络请求的接口类 -->
<-- AccessApi.java -->
public interface AccessApi {
// 注解GET:采用Get方法发送网络请求
// Retrofit把网络请求的URL分成了2部分:1部分baseurl放在创建Retrofit对象时设置;另一部分在网络请求接口设置(即这里)
// 如果接口里的URL是一个完整的网址,那么放在创建Retrofit对象时设置的部分可以不设置
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
// 接受网络请求数据的方法
Call<JavaBean> getCall();
// 返回类型为Call<*>,*是解析得到的数据类型,即JavaBean
}
//MainActivity中
<-- 步骤3:在MainActivity创建接口类实例 -->
<--得到上面创建的Retrofit对象-->
AccessApi NetService = retrofit.create(AccessApi.class);
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象 -->
Call<JavaBean> call = NetService.getCall();
Retrofit是通过外观模式&代理模式使用create()方法创建网络请求接口的实例(同时网络请求接口里设置的注解进行网络请求参数的配置);
AccessApi NetService = retrofit.create(AccessApi.class)源码分析
public <T> T create(final Class<T> service) {
if (validateEagerly) {
// 判断是否需要提前验证
eagerlyValidateMethods(service);
// 具体方法作用:
// 1. 给接口中每个方法的注解进行解析并得到一个ServiceMethod对象
// 2. 以Method为键将该对象存入LinkedHashMap集合中
// 特别注意:如果不是提前验证则进行动态解析对应方法(下面会详细说明),得到一个ServiceMethod对象,最后存入到LinkedHashMap集合中,类似延迟加载(默认)
}
// 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例 (并最终返回)
// 该动态代理是为了拿到网络请求接口实例上所有注解
return (T) Proxy.newProxyInstance(
service.getClassLoader(), // 动态生成接口的实现类
new Class<?>[] { service }, // 动态创建实例
new InvocationHandler() { // 将代理类的实现交给 InvocationHandler类作为具体的实现(下面会解释)
private final Platform platform = Platform.get();
// 在 InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作
// 如统计执行时间、进行初始化和清理、对接口调用进行检查等。
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// 下面会详细介绍 invoke()的实现
// 即下面三行代码
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
// 特别注意
// return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
// 可以解读为:getProxyClass(loader, interfaces) .getConstructor(InvocationHandler.class).newInstance(invocationHandler);
// 即通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
// 先记住结论,在讲解步骤4的时候会再次详细说明
<-- 关注点1:eagerlyValidateMethods() -->
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); }
// 将传入的ServiceMethod对象加入LinkedHashMap<Method, ServiceMethod>集合
// 使用LinkedHashMap集合的好处:lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现
}
}
-
外观模式 定义一个统一接口,外部与通过该统一的接口对子接口系统里的其他接口进行访问, Retrofit对象的外观=retrofit.create() ,通过这一外观方法就可以在内部调用各个方法创建网络请求接口的实例和配置网络请求参数,
-
代理模式, 通过访问代理对象的方式来间接访问目标对象
- 动态代理: 代理类在程序运行前不存在,运行时由程序动态生成的代理方法,
- 静态代理: 代理类在程序运行前已经存在的代理方式
return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
通过代理模式中的动态代理模式,动态生成接口的代理类,并将代理类的实例创建给InvocationHandler类作为具体的实现并将最终返回一个动态代理对象.
InvocationHandler类 # invoke()方法具体实现
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// 将详细介绍下面代码
// 关注点1
// 作用:读取网络请求接口里的方法,并根据前面配置好的属性配置serviceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
// 关注点2
// 作用:根据配置好的serviceMethod对象创建okHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 关注点3
// 作用:调用OkHttp,并根据okHttpCall返回rejava的Observe对象或者返回Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
- :ServiceMethod serviceMethod = loadServiceMethod(method)
<-- loadServiceMethod(method)方法讲解 -->
// 一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// loadServiceMethod(method)负责加载 ServiceMethod:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
// 设置线程同步锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
// ServiceMethod类对象采用了单例模式进行创建
// 即创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例
// 若没缓存,则通过建造者模式创建 serviceMethod 对象
if (result == null) {
// 下面会详细介绍ServiceMethod生成实例的过程
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
// 这里就是上面说的创建实例的缓存机制:采用单例模式从而实现一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// 注:由于每次获取接口实例都是传入 class 对象
// 而 class 对象在进程内单例的,所以获取到它的同一个方法 Method 实例也是单例的,所以这里的缓存是有效的。
- ServiceMethod类构造函数–详细分析
<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory; // 网络请求工厂
final CallAdapter<?> callAdapter;
// 网络请求适配器工厂
// 具体创建是在new ServiceMethod.Builder(this, method).build()最后的build()中
// 下面会详细说明
private final Converter<ResponseBody, T> responseConverter;
// Response内容转换器
// 作用:负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
private final HttpUrl baseUrl; // 网络请求地址
private final String relativeUrl; // 网络请求的相对地址
private final String httpMethod; // 网络请求的Http方法
private final Headers headers; // 网络请求的http请求头 键值对
private final MediaType contentType; // 网络请求的http报文body的类型
private final ParameterHandler<?>[] parameterHandlers;
// 方法参数处理器
// 作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
// 下面会详细说明
// 说明:从上面的成员变量可以看出,ServiceMethod对象包含了访问网络的所有基本信息
<-- ServiceMethod 类的构造函数 -->
// 作用:传入各种网络请求参数
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.responseConverter = builder.responseConverter;
this.baseUrl = builder.retrofit.baseUrl();
this.relativeUrl = builder.relativeUrl;
this.httpMethod = builder.httpMethod;
this.headers = builder.headers;
this.contentType = builder.contentType; .
this.hasBody = builder.hasBody; y
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
- servermethod 类的Builder方法
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 获取网络请求接口方法里的注释
this.methodAnnotations = method.getAnnotations();
// 获取网络请求接口方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取网络请求接口方法里的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
- serviceMethod类的build()
// 作用:控制ServiceMethod对象的生成流程
public ServiceMethod build() {
callAdapter = createCallAdapter();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器 -->关注点1
responseType = callAdapter.responseType();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
responseConverter = createResponseConverter();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器 -->关注点3
// 构造 HTTP 请求时,我们传递的参数都是String
// Retrofit 类提供 converter把传递的参数都转化为 String
// 其余类型的参数都利用 Converter.Factory 的stringConverter 进行转换
// @Body 和 @Part 类型的参数利用Converter.Factory 提供的 requestBodyConverter 进行转换
// 这三种 converter 都是通过“询问”工厂列表进行提供,而工厂列表我们可以在构造 Retrofit 对象时进行添加。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 解析网络请求接口中方法的注解
// 主要是解析获取Http请求的方法
// 注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded
// 处理主要是调用方法 parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值
int parameterCount = parameterAnnotationsArray.length;
// 获取当前方法的参数数量
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
// 为方法中的每个参数创建一个ParameterHandler<?>对象并解析每个参数使用的注解类型
// 该对象的创建过程就是对方法参数中注解进行解析
// 这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
<-- 总结 -->
// 1. 根据返回值类型和方法标注从Retrofit对象的的网络请求适配器工厂集合和内容转换器工厂集合中分别获取到该方法对应的网络请求适配器和Response内容转换器;
// 2. 根据方法的标注对ServiceMethod的域进行赋值
// 3. 最后为每个方法的参数的标注进行解析,获得一个ParameterHandler<?>对象
// 该对象保存有一个Request内容转换器——根据参数的类型从Retrofit的内容转换器工厂集合中获取一个Request内容转换器或者一个String内容转换器。
}
<-- 关注点1:createCallAdapter() -->
private CallAdapter<?> createCallAdapter() {
// 获取网络请求接口里方法的返回值类型
Type returnType = method.getGenericReturnType();
// 获取网络请求接口接口里的注解
// 此处使用的是@Get
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
// 下面会详细说明retrofit.callAdapter() -- >关注点2
}
...
<-- 关注点2:retrofit.callAdapter() -->
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// 创建 CallAdapter 如下
// 遍历 CallAdapter.Factory 集合寻找合适的工厂(该工厂集合在第一步构造 Retrofit 对象时进行添加(第一步时已经说明))
// 如果最终没有工厂提供需要的 CallAdapter,将抛出异常
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
<-- 关注点3:createResponseConverter() -->
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
// responseConverter 还是由 Retrofit 类提供 -->关注点4
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) {
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
<-- 关注点4:responseBodyConverter() -->
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 获取Converter 过程:(和获取 callAdapter 基本一致)
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
// 遍历 Converter.Factory 集合并寻找合适的工厂(该工厂集合在构造 Retrofit 对象时进行添加(第一步时已经说明))
// 由于构造Retroifit采用的是Gson解析方式,所以取出的是GsonResponseBodyConverter
// Retrofit - Converters 还提供了 JSON,XML,ProtoBuf 等类型数据的转换功能。
// 继续看responseBodyConverter() -->关注点5
}
<-- 关注点5:responseBodyConverter() -->
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
// 根据目标类型,利用 Gson#getAdapter 获取相应的 adapter
return new GsonResponseBodyConverter<>(gson, adapter);
}
// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
通过上面一系列的配置,serviceMethod method=new serviceMethod.loadServiceMethod(method)对象, 即API api =retrofit.create(api.class)中create(api.class)中的serviceMethod对象配置完成.
配置OkhttpCall okhttpCall= new okHttpCall(serviceMethod,agrs)
<--OkHttpCall类 -->
public class OkHttpCall {
private final ServiceMethod<T> serviceMethod; // 含有所有网络请求参数信息的对象
private final Object[] args; // 网络请求接口的参数
private okhttp3.Call rawCall; //实际进行网络访问的类
private Throwable creationFailure; //几个状态标志位
private boolean executed;
private volatile boolean canceled;
<--OkHttpCall构造函数 -->
public OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
// 传入了配置好的ServiceMethod对象和输入的请求参数
this.serviceMethod = serviceMethod;
this.args = args;
}
reture serviceMethod.callAdapter.adapt(okHttpCall) 分析:
得到OkhttpCall对象传递给serviceMethod对象中对应的网络请求适配器工厂的adapt(); 返回类型android默认是call<> 若是套用RXJava 则返回的是observable<>
<-- adapt()详解-->
public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.delegate = delegate;
// 把上面创建并配置好参数的OkhttpCall对象交给静态代理delegate
// 静态代理和动态代理都属于代理模式
// 静态代理作用:代理执行被代理者的方法,且可在要执行的方法前后加入自己的动作,进行对系统功能的拓展
this.callbackExecutor = callbackExecutor;
// 传入上面定义的回调方法执行器
// 用于进行线程切换
}
采用了装饰模式,ExecutorCallbackCall=装饰者 而里面真正执行网络请求的还是OkhttpCall
使用装饰者的原因是:希望okhttpcall发送请求时做一些额外的操作,这里的额外操作是线程的转换,即将子线程切换到主线程.
//OKhttpcall的enqueue是进行网络异步请求的,当你调用okHttpcall.enqueue()时,回调的callback是在主线程中,需要通过Handler转换到主线程进行回调,ExcutorCallBackCall就是用于线程回调
//当然以上是原生retrofit使用的线程切换方式,如果使用Rxjava,那就不会用到这个ExcutorCallbackCall而是RxJava的call.
call call =NetService.getCall();
- NetService对象实际上是动态代理对象Proxy.newInstance(),并不是真正的网络请求接口创建的对象.
- 当NetService对象调用自身的getCall时会被动态代理对象Proxy.newInstance()拦截,然后调用自身的Invocationhandler#.invoke();
- invoke(object proxy,method method,object…args) proxy是代理对象,method调用的getcall,args是方法中的参数
- 接下来利用反射获取到getcall()的注解信息,配合args参数创建serviceMethod对象
最终创建并返回一个okHttpCall类型的call对象
注意: OkhttpCall是okhttp的包装类
创建爱你了OkhttpCall类型的call对象还不能发送网络请求,需要创建request对象才能发送网络请求.
总结
- 动态创建爱你网络请求接口的实例(代理模式-动态代理)
- 创建serviceMethod对象(建造者模式&单例模式(缓存机制))
- 对serviceMethod对象进行网络请求参数的配置,通过解析网络请求接口方法的参数,返回值和注解类型,从retrofit对象中获取相应的网络请求的url地址.网络请求执行器,网络请求适配器&数据转换器(策略模式)
- 最终创建并返回一个OKhttpCall类型的网络请求对象.
执行网络请求
同步请求 OKHttpCall.execute()
-
发送网络请求过程
- 对请求网络接口中的每个参数利用Parameterhandler进行解析,再根据ServiceMethod对象创建一个Okhttp的request对象
- 使用Okhttp的request发送网络请求
- 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的到数据,最终得到一个Response对象
Response<JavaBean> response = call.execute(); //包含发送同步请求的三个步骤
-
源码分析
@Override public Response<T> execute() throws IOException { okhttp3.Call call; // 设置同步锁 synchronized (this) { call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); // 步骤1:创建一个OkHttp的Request对象请求 -->关注1 } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } return parseResponse(call.execute()); // 步骤2:调用OkHttpCall的execute()发送网络请求(同步) // 步骤3:解析网络请求返回的数据parseResponse() -->关注2 } <-- 关注1:createRawCall() --> private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); // 从ServiceMethod的toRequest()返回一个Request对象 okhttp3.Call call = serviceMethod.callFactory.newCall(request); // 根据serviceMethod和request对象创建 一个okhttp3.Request if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } <-- 关注2:parseResponse()--> Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); // 收到返回数据后进行状态码检查 // 具体关于状态码说明下面会详细介绍 int code = rawResponse.code(); if (code < 200 || code >= 300) { } if (code == 204 || code == 205) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); // 等Http请求返回后 & 通过状态码检查后,将response body传入ServiceMethod中,ServiceMethod通过调用Converter接口(之前设置的GsonConverterFactory)将response body转成一个Java对象,即解析返回的数据 // 生成Response类 return Response.success(body, rawResponse); } catch (RuntimeException e) { ... // 异常处理 } }
- serviceMethod几乎保存了一个网络请求所需要的数据
- 发送网络请求时,okHttpCall需要从serviceMethod中获得一个request对象
- 数据解析时,还需要通过serviceMethod使用converter(数据转换器)转换成java对象进行数据解析.
- 为了提高效率,retrofit还会对解析过的请求serviceMethod进行缓存,存放在Map<Method,serviceMethod>serviceMethodCahe =ne linkedHashMap<>();对象中,
- 请求中2开头 表示成功,3表示重定向,4表示错误,5.6表示服务器错误.
异步请求 OkHttpCall.enqueue();
- 发送请求的过程
- 对网络请求接口的方法中的每个参数利用对应parameterHandler进行解析,在根据serviceMethod对象创建一个OKhttp的request对象
- 使用okhttp的request发送网络请求,
- 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终的到一个response对象
- 若使用RXJAVA则直接回调到主线程中,进行线程切换从而到主线程处理返回的数据结果
异步和同步请求过程类似,唯一不同,异步请求会将回调方法交给回调执行器在指定的线程中执行.(UI线程)
-
具体使用
call.enqueue(new Callback<JavaBean>() { @Override public void onResponse(Call<JavaBean> call, Response<JavaBean> response) { System.out.println(response.isSuccessful()); if (response.isSuccessful()) { response.body().show(); } else { try { System.out.println(response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } ; } }
从上分析call是一个静态代理
使用代理的作用是:在okhttpcall发送网络请求的前后进行额外操作.(线程的切换,从UI线程切换到主线程对返回的数据结果进行处理)
- 源码分析
<-- call.enqueue()解析 --> @Override public void enqueue(final Callback<T> callback) { delegate.enqueue(new Callback<T>() { // 使用静态代理 delegate进行异步请求 ->>分析1 // 等下记得回来 @Override public void onResponse(Call<T> call, final Response<T> response) { // 步骤4:线程切换,从而在主线程显示结果 callbackExecutor.execute(new Runnable() { // 最后Okhttp的异步请求结果返回到callbackExecutor // callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理(如显示在Activity等等),即进行了线程切换 // 具体是如何做线程切换 ->>分析2 @Override public void run() { if (delegate.isCanceled()) { 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); } }); } }); } <-- 分析1:delegate.enqueue()解析 --> @Override public void enqueue(final Callback<T> callback) { okhttp3.Call call; Throwable failure; // 步骤1:创建OkHttp的Request对象,再封装成OkHttp.call // delegate代理在网络请求前的动作:创建OkHttp的Request对象,再封装成OkHttp.call synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { call = rawCall = createRawCall(); // 创建OkHttp的Request对象,再封装成OkHttp.call // 方法同发送同步请求,此处不作过多描述 } catch (Throwable t) { failure = creationFailure = t; } } // 步骤2:发送网络请求 // delegate是OkHttpcall的静态代理 // delegate静态代理最终还是调用Okhttp.enqueue进行网络请求 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { // 步骤3:解析返回数据 response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); } @Override public void onFailure(okhttp3.Call call, IOException e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } }); } // 请回去上面分析1的起点 <-- 分析2:异步请求后的线程切换--> // 线程切换是通过一开始创建Retrofit对象时Platform在检测到运行环境是Android时进行创建的:(之前已分析过) // 采用适配器模式 static class Android extends Platform { // 创建默认的回调执行器工厂 // 如果不将RxJava和Retrofit一起使用,一般都是使用该默认的CallAdapter.Factory // 后面会对RxJava和Retrofit一起使用的情况进行分析 @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { return new ExecutorCallAdapterFactory(callbackExecutor); } @Override public Executor defaultCallbackExecutor() { // 返回一个默认的回调方法执行器 // 该执行器负责在主线程(UI线程)中执行回调方法 return new MainThreadExecutor(); } // 获取主线程Handler static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { // Retrofit获取了主线程的handler // 然后在UI线程执行网络请求回调后的数据显示等操作。 handler.post(r); } } // 切换线程的流程: // 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象 // 2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程处理返回结果(如显示在Activity等等) }
总结
Retrofit本质上是一个restful的http其网络请求框架的封装,即通过大量的设计模式封装的okhttp,使用简洁易用,
源码分析表如下:
步骤 | 任务 | 具体过程 | 使用的设计模式 |
---|---|---|---|
步骤一 | 创建一个Retrofit实例 | 通过内部类Builder建立一个Retrofit实例(建造者模式)具体过程是配置了: 1. 平台类型对象(Platform-Android) 2. 网络请求的url地址(baseurl) 3.网络请求工厂(callfactory)默认使用okhttpcall(工厂方法模式) 4.网络请求适配器工厂集合(adapterFactories)默认是ExecutorCallFactories 5.数据转换工厂的集合(converterFactories)本质是配置了数据转换工厂 6.回调方法执行器(callbackExecutor)默认回调方法执行器的作用是进行下次呢很难过的切换(子线程–>主线程) |
建造者模式, 工厂模式 |
步骤二 | 创建网络请求接口的实例(通过解析配置网络请求参数) | Retrofit采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体如下: 1.动态创建网络请求接口实例,(代理模式-动态代理#innovationHandler对象#invoke()) 2.创建serviceMethod对象(建造者模式&单例模式(缓存机制)) 3.对serviceMethod对象进行网络请求参数配置,通过解析网络请求参数接口方法的参数,返回值的注解类型,从retrofit对象中获取对应的网络请求的URl地址,网络请求执行器,网络请求适配器&数据转换器(策略模式) 4.对serviceMethod对象加入线程切换操作,便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理(装饰模式) 5.最终创建并返回一个OKHttpcall类型的网络请求对象 |
外观模式,代理模式,建造者模式,单例模式,装饰模式 |
步骤三 | 发送网络请求(同步) | 代理模式,适配器模式,装饰模式 | |
发送网络请求(异步) | 1.通过静态delegate代理对网络请求接口的方法中的每隔参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个okhttp的request对并封装成OkHttp.call对象(代理模式) 2.使用静态delegate通过okhttp.call对象发送网络请求(代理模式) |
||
步骤四 | 解析数据 | 对返回的数据使用之前设置的数据转化器(GsonConverterFactory)解析返回数据,最终的到一个Response对象 | |
步骤五 | 切换线程(同步) | 无线程切换 | |
切换线程(异步) | 使用回调器进行线程切换(子线程–>主线程)(适配器,装饰模式) | ||
步骤六 | 处理结果(同步) | 通过Response对象处理返回的数据结果 | |
处理结果(异步) | 在主线程处理返回的数据结果 |