一、前言
二、源码解析
1、构建Retrofit对象
1.1、Retrofit类的成员变量
1.2、Retrofit.Builder
1.3、Builder.build()方法
2、创建网络请求接口实例
2.1、动态代理模式
2.2、接口实例的创建
2.3、创建ServiceMethod
2.3.1、RequestFactory.parseAnnotations解析注解
2.3.2、HttpServiceMethod.parseAnnotations创建ServiceMethod
2.4、ServiceMethod.invoke()
3、发起网络请求
三、总结
一、前言
Retrofit已经出来很久了,相信我们大家都已经知道它 内部的网络请求是通过 OkHttp 完成, 自身仅负责的是网络请求接口的封装 。 今天我们就来一起分析一下Retrofit的源码,Retrofit源码的版本为2.7.1。
retrofit的使用我们就不再做过多的介绍,就简单列一下retrofit使用的四个基本步骤,然后从这四个步骤开始分析
1.创建api接口
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
2.创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
3.创建api的实现
GitHubService service = retrofit.create(GitHubService.class);
4.发起网络请求
Call> repos = api.listRepos("test");
repos.execute() 或者 repos.enqueue()
对于这四步基本使用我们应该都知道,现在我们就按照上述过程来分析对应的源码。看源码之前,我们最好是带着问题去看,对于一些API调用链,理清思路即可,要不然很容易一头扎进源码细节出不来。 针对Retrofit我们可以像自己提出四个问题,然后带着问题去分析源码:
1.Retrofit的原理是什么
2.Retrofit 是怎么解析注解的,并把它组装成网络请求参数
3.用到了哪些设计模式呢,为什么用代理模式,代理模式的作用是什么
4.rxjava和retrofit如何结合来支持RxJava的
二、源码分析
1.构建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
对于构建过程我们可以从这几个方面来分析
1.Retrofit的成员变量
2.构建Builder
3.build的过程
1.1Retrofit的成员变量
//serviceMethodCache: 缓存ServiceMethod中一些网络请求的相关配置、网络请求的方法、数据转换器和网络请求适配器等等
private final Map> serviceMethodCache = new ConcurrentHashMap<>();
// Retrofit默认使用OkHttp,callFactory实际上就是OkHttpClient
final okhttp3.Call.Factory callFactory;
// 网络请求的url地址
final HttpUrl baseUrl;
// 数据转换器工厂的集合
final List converterFactories;
// 网络请求适配器工厂的集合
//在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
final List callAdapterFactories;
// 回调方法执行器 , 用来切换线程的
final @Nullable Executor callbackExecutor;
// 是否缓存创建的ServiceMethod
final boolean validateEagerly;
1.2Retrofit.Builder
在Retrofit.Builder中我们可以看到 Builder 构造函数中调用了 Platform.get() ,然后赋值给自己的 platform 变量
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private @Nullable HttpUrl baseUrl;
private final List converterFactories = new ArrayList<>();
private final List callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
...
接下来我们来看看 Platform 类,我截取它的主要的代码,我们一起来看一下
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
private final boolean hasJava8Types;
Platform(boolean hasJava8Types) {
this.hasJava8Types = hasJava8Types;
}
// 返回默认的 Executor 对象,正是 Retrofit 的成员变量回调执行器,它的内部采用 Handler 负责子线程到主线程的切换工作
@Nullable Executor defaultCallbackExecutor() {
return null;
}
//返回默认的 CallAdapter.Factory 对应Retrofit 成员变量中的网络请求适配器工厂集合callAdapterFactories
List extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
//返回默认的 Converter.Factory 对应Retrofit 成员变量中的网络请求数据转换器集合converterFactories
List extends Converter.Factory> defaultConverterFactories() {
return hasJava8Types
? singletonList(OptionalConverterFactory.INSTANCE)
: emptyList();
}
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
- Platform.get() 调用了 findPlatform() 方法,然后判断如果是 Android 平台会返回一个 Android() 对象
- Android()对象的defaultCallbackExecutor:实现了默认的Executor线程切换器,它对应着Retrofit成员变量中的callbackExecutor,我们可以看出来其内部采用 Handler 负责子线程到主线程的切换工作。
- Android()的构造函数:判断当前sdk版本是否大于Android 7.0 ,然后赋值给父类Platfrom中的hasJava8Types属性,而Platfrom中的hasJava8Types 主要在Platfrom中2个方法中使用:
(1) defaultCallAdapterFactories:返回的是默认的 CallAdpter.Factory 的集合,就是Retrofit 成员变量中的网络请求适配器工厂集合callAdapterFactories。
(2) defaultConverterFactories:返回的是默认的 Converter.Factory 的集合,就是Retrofit 成员变量中的数据转换器集合converterFactories。
1.3 build的过程
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
至此,Retrofit 的创建流程就完成了,build方法中配置了Retrofit类的所有成员变量,
serviceMethodService:暂时为空
callFactory:默认OkHttpClient 对象
baseUrl:根据配置的 baseUrl,构建成okhttp的HttpUrl 对象
callAdapterFactories:配置的和默认的网络请求适配器工厂集合
converterFactories:配置的和默认的数据转换器工厂集合
callbackExecutor:MainThreadExecutor 对象
validateEagerly:默认 false
2.创建网络请求接口实例
我们都知道retrofit.create() 这里利用了动态代理,通过动态代理Retrofit将一个普通的Java Interface转化为了Http请求。那么问题就来了,动态代理到底是什么呢,所以在看create源码之前,这里我们就先来简单了解一下设计模式中代理模式,这样才会有利于我们去理解源码。
2.1动态代理模式
代理模式定义:
为其他对象提供一种代理以控制这个对象的访问
代理模式的角色:
Subject:代理者与被代理者共同实现的接口,可以理解为需要代理的行为;
RealSubject:被代理者,其为具有某种特定行为的实现者;
Proxy:代理者,其会全权代理RealSubject所具有的功能,在实现其功能的基础上做一些额外的工作;
Client:客户端,客户端访问代理者与访问被代理者具有类似的效果,其无法区分访问的是代理者还是被代理者。
它的结构图下图很清晰的表示了出来
代理模式的应用最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。对于代理,根据创建代理类的时间点, 可以分为静态代理和动态代理。
静态代理:就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
动态代理:代理类在程序运行时创建的代理方式被成为动态代理。
我们这里着重说一下动态代理 ,动态代理的创建其实就分为2步
第一步通过Proxy.getProxyClass创建代理类的class对象
第二步通过反射获得这个类的构造方法并传入InvocationHandler的实现从而得到代理的实例对象
然后我们看一下下面的的例子:将GitHubService转化为一个代理对象
public interface GitHubService {
String listRepos(String user);
}
1.通过Proxy.getProxyClass生成GitHubService 代理对象的Class对象:
Class mProxyClass = Proxy.getProxyClass(GitHubService.class.getClassLoader(),GitHubService.class );
2.第二步通过反射获得这个类的构造方法并传入InvocationHandler的实现类从而获取代理类的实例
GitHubService mServcieImpl = (GitHubService) mProxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String s1 = (String) args[0];
return "代理类统一处理:" +s1 ;
}
});
第一步我们通过Proxy生成了mProxyClass ,Proxy类的getProxyClass方法就创建了一个动态代理对象。我们点进去getProxyClass可以看到它的源码中最主要的一句是Class> cl = getProxyClass0(loader, intfs),就是这句话创建了代理类。
这个类的产生就是整个动态代理的关键,这个类文件是缓存在java虚拟机中的, 我们利用这个方法把System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true") 将运行时生成的动态代理类mProxyClass的Class文件保存下来 我们看一下动态生成的$Proxy0里的主要内容
public final class $Proxy0 extends Proxy implements GitHubService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final String listRepos(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.java.learn.GitHubService").getMethod("listRepos", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
代码很简单,我们可以看到动态生成的代理类也实现了GitHubService接口,并且它的构造函数中传的是InvocationHandler。然后,我们看一下代理类的listRepos方法 这里的super.h 就是父类Proxy中InvocationHandler 。 而父类Proxy中InvocationHandler是从 $Proxy0的构造方法中传入。看到这是不是就明白了当我们调用代理类的listRepos方法时 就会调用InvocationHandler 对象的invoke方法并传入方法对应的Method对象和参数。而代理类的InvocationHandler 正是我们第二步中传入的InvocationHandler的实现类。这样一来我们就知道每一个动态代理类都必须要实现InvocationHandler这个接口, 然后当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler的 invoke 方法来进行调用。这就是我们动态代理的基本原理。那动态代理优势在哪呢?我们可以看一下 《深入理解Java虚拟机》一书中的描述:
2.2接口实例的创建
简单了解完了动态代理 我们再来继续来看Retrofit中create的源码 。
GitHubService service = retrofit.create(GitHubService.class);
public T create(final Class 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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
看完这里我们是不是就知道 create这里也是用的动态代理,返回的正是我们刚才所看到的$Proxy0的实例 ,说明create这里的原理就是通过动态代理生成了GitHubService代理类的Class二进制流,并且加载到虚拟机中形成代理类的Class对象,再通过反射得到代理类对象,而该代理类即实现了GitHubService,并且持有了InvocationHandler的引用。
这样 当我们开始调用时
Call> repos = api.listRepos("test");
就会执行到InvocationHandler引用的对象的invoke方法。
对于invoke方法其中最主要的是下面这一句
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
我们可以从loadServiceMethod和 invoke我们分别来分析一下
2.3创建ServiceMethod
我们先来看loadServiceMethod(method)
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;
}
abstract class ServiceMethod {
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
我们可以看到loadServiceMethod 返回的是ServiceMethod对象,ServiceMethod是一个抽象类,它只有两个方法,一个是parseAnnotations(Retrofit retrofit, Method method),一个是抽象的方法invoke(), 对于ServiceMethod.parseAnnotations 方法里主要是两个方法:
RequestFactory.parseAnnotations
HttpServiceMethod.parseAnnotations 我们来分别看下这两个方法
2.3.1通过RequestFactory.parseAnnotations解析注解配置
RequestFactory.parseAnnotations 方法主要是通过 RequestFactory 解析注解配置,就是我们常用的@GET @POST @Multipart、 封装到 RequestFactory 对象中,然后将其返回。
然后我们看一下RequestFactory内部怎么实现的
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
这里有几个重要的参数:
retrofit:retrofit实例
method:接口方法
methodAnnotations:接口方法的注解,在retrofit里一般为请求方式
parameterTypes:参数类型
parameterAnnotationsArray:参数注解数组,一个参数可能有多个注解
我们先从build()的方法开始,我把注解处理的主要代码截取了出来我们来看下
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
}
我们可以看第一段build其中主要有两个方法
解析方法上的注解parseMethodAnnotation()
解析参数中的注解parseParameter()
parseMethodAnnotation-方法注解处理
private void parseMethodAnnotation(Annotation annotation) {
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
....
else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
....
对于parseMethodAnnotation它的解析主要有三类
第一类开头是例如DELETE、GET、POST、HEAD这些,注解处理走的是parseHttpMethodAndPath方法
第二类是@header,执行的是parseHeaders方法
第三类就@Multipart和@FormUrlEncoded,就是改了一下标志位。
我们继续来看下parseHttpMethodAndPath方法和parseHeader方法
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
...
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
我们可以看parseHttpMethodAndPath,从名字就可以看出来,这个方法应该主要拼装当前http的请求方式(POST或GET之类)以及url的设置,这里最主要就是给relativeUrl 赋值,对应的value正是由((GET) annotation).value()这样得到的,其中有一段正则的检查,正则的完整表达式如下:{([a-zA-Z][a-zA-Z0-9_-]*)} , 我们都知道retrofit注解里是可以放{}占位符的,当下面这样?后面出现占位符就会抛出异常,也就是说?后面不允许占位符
public interface IpServiceForPath {
@GET("{path}/getIpInfo.php?ip={ip}")
Call getIpMsg(@Path("path") String path);
}
这样通过这个方法我们就得到了网络请求的相对地址,类似于{path}/getIpInfo.php这样的。里面的“{path}”是我们parseParameter中需要赋值的变量
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
int colon = header.indexOf(':');
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw methodError(method,
"@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
}
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
if ("Content-Type".equalsIgnoreCase(headerName)) {
try {
contentType = MediaType.get(headerValue);
} catch (IllegalArgumentException e) {
throw methodError(method, e, "Malformed content type: %s", headerValue);
}
} else {
builder.add(headerName, headerValue);
}
}
return builder.build();
}
parseHeader这个方法返回 的是OkHttp的Headers。整个方法没什么难以理解的,就是检查了下格式,然后把一个个键值对放进去而已,对于“Content-Type"做了特殊处理,根据这个type的value值设置了ServiceMethod.contentType。
parseParameter-参数注解处理
前面我们说到RequestFactory Build方法里有parseMethodAnnotation方法和parseParameter方法,接下来我们看parseParameter
private @Nullable ParameterHandler> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
...
result = annotationAction;
}
...
return result;
}
@Nullable
private ParameterHandler> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
...
Converter, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
} else if (annotation instanceof Query) {
...
Class> rawParameterType = Utils.getRawType(type);
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
...
Converter, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
...
}
...
}
static final class Query extends ParameterHandler {
private final String name;
private final Converter valueConverter;
private final boolean encoded;
Query(String name, Converter valueConverter, boolean encoded) {
this.name = Objects.requireNonNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String queryValue = valueConverter.convert(value);
if (queryValue == null) return; // Skip converted but null values
builder.addQueryParam(name, queryValue, encoded);
}
}
parseParameter就是负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数,他核心逻辑是通过parseParameterAnnotation()方法解析参数注解生成ParameterHandler对象,ParameterHandler是一个抽象类,ParameterHandler的子类封装了参数的数据和数据的处理过程,例如子类ParameterHandler.Query就封装了@Query注解的参数,Retrofit 为方法中的每个参数创建一个ParameterHandler>对象并解析每个参数使用的注解类型。这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url 。我们可以看到里面有一个apply 方法,那apply 什么时候被调用呢。在我们 后面通过OkHttpCall进行同步或者异步请求时,会有一个过 createRawCall ,我们点进他的源码可以看到执行了每个参数对应的ParameterHandler的 apply 方法,赋值到RequestBuilder 然后就构造一个 Request 对象。
这基本上就是注解的处理过程
2.3.2HttpServiceMethod.parseAnnotations创建ServiceMethod
看完了ServiceMethod.parseAnnotations中的RequestFactory.parseAnnotations,我们再来看另一个地方,就是最后一句
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
HttpServiceMethod 的 parseAnnotations() 方法中创建了ServiceMethod,他里面有两个主要的方法就是
createCallAdapter() 生成请求适配器callAdapter
createResponseConverter() 生成响应体(Response)的数据转换器Converter
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
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, CallAdapter 顾名思义,它就是网络请求执行器的适配器,Retrofit中默认的网络请求执行器是OkHttpCall,CallAdapter可以将OkHttpCall转换成适合被不同平台来调用的网络请求执行器形式。说到这不得不提一下适配器模式,适配器模式一句话:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。适配器模式简单来说,就是将一个已存在的东西转换成适合我们使用的东西。 我们常用的就是RecyclerView中的Adapter。 我们Retrofit中的CallAdapter就是将OkHttpCall转化成适合不同平台来调用
的网络执行器 。 Retrofit中用了适配器模式把OkHttpCall轻松适配到了RxJava的Observable、Android的ExecutorCallbackCall、Java8的CompletableFuture,Guava,如果以后要扩展就可以在继续适配就行,非常容易扩展。Retrofit跟据网络接口方法的返回值类型来选择具体要用哪种 CallAdapterFactory,然后获取具体的 CallAdapter。在Retrofit中有四种CallAdapterFactory: DefaultCallAdapterFactory(默认)、Java8CallAdapterFactory、RxJavaCallAdapterFactory、GuavaCallAdapterFactory
在前面的Platform我们知道Retrofit 内置了两种默认的适配器工厂:CompletableFutureCallAdapterFactory(系统版本大于等于24时生效)和DefaultCallAdapterFactory,当然我们还可以在Build的时候设置RxJava2CallAdapterFactory,这样一来retrfit也就和RxJava结合到一起,我们在这里看一下DefaultCallAdapterFactory的代码
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
@Override public @Nullable CallAdapter, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call or Call extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter
creatCallAdapter :看到这里我们是不是就明白了,creatCallAdapter 通过nextCallAdapter中的CallAdapter.Factory.get来得到calladapter,而DefaultCallAdapterFactory 中get方法返回的是一个新的CallAdapter实例 。在实例的adapt函数中,把Retrofit中用来访问网络的OkHttpCall,转换为一个ExecutorCallbackCall,OkHttpCall和ExecutorCallbackCall都实现了retrofit2.Call接口,结果就出现了从OkHttpCall转换为Call
至此,我们可以理解Retrofit根据接口定义动态生产Call网络请求工作对象的原理了,其实就是通过适配器把retrofit2.Call对象转换为目标对象。
createResponseConverter:根据网络请求接口方法的返回值和注解类型从 Retrofit 对象中获取对应的数据转换器,和创建 CallAdapter 基本一致,遍历 Converter.Factory 集合并寻找具体的 Converter。
2.4ServiceMethod.invoke()
看完loadSerovice我们接着来看invoke()方法
ServiceMethod 是一个抽象类,invoke() 是一个抽象方法,具体实现在子类中。
@Override final @Nullable ReturnT invoke(Object[] args) {
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
首先 创建了一个 OkHttpCall 对象,这个 OkHttpCall 是 Retrofit 的 Call, 我们去看OkHttpCall的源码
final class OkHttpCall implements Call {
它实现了call接口
public interface Call extends Cloneable {
Response execute() throws IOException;
void enqueue(Callback callback);
boolean isExecuted();
void cancel();
boolean isCanceled();
Call clone();
Request request();
}
和Okhttp的Call方法很像吧 然后我们去看OKhttpCall中的request()等方法的实现可以知道retrofit的网络请求其实就是OKHTTP实现的,篇幅原因这里就不在截取代码了
接下来我们继续回到invoke方法,我们来看看他的adapt() 方法
adapt() 是一个 抽象方法,他的具体实现在 HttpServiceMethod 的子类中。
我们可以看到HttpServiceMethod 有三个子类 非协程的情况是 CallAdapted, 协程的时候是 SuspendForResponse 以及 SuspendForBody 类。
CallAdapted:我们通过上面的分析知道,DefaultCallAdapterFactory,RxJava2CallAdapterFactory中的get中会创建calladapter实例,其中的adapt方法就正是把OKhttpCall转换为Call
SuspendForResponse:首先根据传递进来的 Call 构造了一个参数为 Response 的 Continuation 对象然后通过 Kotlin 实现的 awaitResponse() 方法将 call 的 enqueue 异步回调过程封装成 一个 suspend 的函数。
SuspendForBody:SuspendForBody 则是根据传递进来的 Call 构造了一个 Continuation 对象然后通过 Kotlin 实现的 await() 或 awaitNullable() 方法将 call 的 enqueue 异步回调过程封装为了一个 suspend 的函数。
3 发起网络请求
Call> call= service.listRepos("octocat");
从前面我们知道Service是动态代理对象,执行listRepos他会调用到 InvocationHandler的 invoke() 方法,得到最终的 Call 对象。
我们看下Call 对象enqueue 方法
很简单,主要就是创建 OkHttp 的 Call 对象,调用 Call 的 enqueue 方法,解析返回结果,执行回调。
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
由上一章我们知道,这里的call实际上就是ExecutorCallAdapterFactory中ExecutorCallbackCall,我们来看下ExecutorCallbackCall.enqueue()方法的代码
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response 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 call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
ExecutorCallbackCall有两个成员变量,callbackExecutor与delegate,通过之前的分析我们知道它们分别对应了MainThreadExecutor和OkHttpCall。MainThreadExecutor.execute()方法将OkHttpCall的请求回调结果发送至主线程, 就是创建 OkHttp 的 Call 对象,调用 Call 的 enqueue 方法,解析返回结果,执行回调
三、总结
至此,Retrofit 的源码基本上就基本上结束了,虽然还有很多细节没有提及,但整体流程应该比较清晰了。相信我们对开头我们提的问题应该也有了答案。
按照我们的分析步骤我们知道retrofit进行网络请求的主要过程
1.通过建造者模式构建一个Retrofit实例
2.通过Retrofit对象的create方法返回一个Service的动态代理对象
3.调用service的方法的时候解析接口注解(方法注解和参数注解)
4.构造ServiceMethod对象生成请求适配器callAdapter,数据转换器Converter
5.ServiceMethod对象注入到OkHttpCall,通过callAdapter将 网络请求对象 进行平台适配,默认是直接返回Call对象
6.调用Okhttp的网络请求方法,通过 回调执行器 切换线程(子线程 ->>主线程)
有不清晰或者不对的地方欢迎指正!