Retrofit框架源码解读
Posted 潇潇凤儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit框架源码解读相关的知识,希望对你有一定的参考价值。
之前对Retrofit框架一直怀有敬重之心,别人能把网络请求框封装得如此好用。以前只知道他内部是调用OkHttp进行网络请求的,可它内部是怎么实现的呢?光会用框架那是初级开发者的水平,总不能当一辈子随时可替代的螺丝钉吧,我也要有一点研究源码的心态,要不到时到时被各大面试官鄙视了。为了更有目的的研究源码,先问自己几个问题,如果闭着眼也能答上来,那算熟练掌握了Retrofit框架。
Question:
1. Retrofit进行网络请求的步骤?
2. Retrofit是怎么封装OkHttp的?
3. Retrofit是怎么和Rxjava对接的?
4. Retrofit中为什么能直接调用接口的方法?
在进行Retrofit框架前,我们先要明白OkHttp网络请求的步骤。
OKHttp网络请求三步骤:
1)将所需参数构建成Request对象
2)根据Request对象构建Call对象
3)执行call.execute/call.enqueue完成同步/异步请求
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();//将所需参数构建成Request对象
Call call = okHttpClient.newCall(request);//据Request对象构建Call对象
call.enqueue(new Callback() //执行call.execute/call.enqueue完成同步/异步请求
@Override
public void onFailure(Call call, IOException e)
@Override
public void onResponse(Call call, Response response) throws IOException
String str = response.body().string();
);
从OkHttp的网络请求步骤中我们可以看出,OkHttp主要是借助 Call进行网络请求的,而Retrofit是对OkHttp进行封装的,那它一定对OkHttp的Call进行了封装,我们来对比下Retrofit的Call接口与OkHttp的Call接口。从下图可以看出,Retrofit内部的Call接口和OkHttp的Call最大区别是Retrofit的Call接口是个泛型接口,提供了泛型的Response<T>和泛型的Callback<T>。Retrofit的具体请求实现类是在OkHttpCall类中。
Retrofit的Call接口结构 OkHttp的Call接口结构 Retrofit的OkHttpCall接口
1. Retrofit进行网络请求的步骤
我们都知道Retrofit框架发起网络请求主要由以下几个步骤构成:
1) 根据请求地址构建Retrofit.Builder对象
2) 创建OkHttpClient对象,根据OkHttpClient对象和Retrofit.Builder对象构建Retrofit对象
3) 利用Retrofit对象生成接口实例
4) 利用接口实例生成OkHttpCall对象
5) 调用OkHttpCall.execute()/enqueue()完成同步或异步请求
//1) 根据请求地址构建Retrofit.Builder对象
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(baseUrl)//网络地址基址
.addConverterFactory(GsonConverterFactory.create())//请求前后对象转换器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create());//返回值的类类型适配器
//2) 创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
//根据OkHttpClient对象和Retrofit.Builder对象构建Retrofit对象
Retrofit retrofit = builder.client(okHttpClient).build();
//3)利用Retrofit对象生成接口实例
GithubService service = retrofit.create(GithubService.class);
//4) 利用接口实例生成OkHttpCall对象
Call<AccountResponse> call = service.account("id");
//5) 调用OkHttpCall.execute()/enqueue()完成同步或异步请求
AccountResponse response = call.execute();//进行网络请求
2、生成接口实例
首先看上面第三步中构建GithubService实例,它主要采用Java动态代理来生成接口的实例,拦截接口的方法,统一解析方法中的注解信息,减少代码的编写。
2.1、生成接口实例
public <T> T create(final Class<T> service)
Utils.validateServiceInterface(service);//验证接口合法性
if (validateEagerly)
eagerlyValidateMethods(service);//验证接口中方法的合法性
//采用java动态代理生成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 Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable
//如果声明方法的类是一个Object类类型,直接按常规调用方法即可
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);
);
2.2、解析接口中声明方法的注解信息,保存到ServiceMethod对象中
2.2.1 从缓存中取
//Retrofit.loadServiceMethod()方法,利用缓存技术,下次调用方法时不需要重新解析
ServiceMethod<?> loadServiceMethod(Method method)
ServiceMethod<?> result = serviceMethodCache.get(method);//从缓存中获取method方法对应的ServiceMethod对象
if (result != null) return result;//如果缓存中存在方法的ServiceMethod对象,则直接返回
synchronized (serviceMethodCache) //用到了单例中的双重校验锁,防止在多线程情况下对方法进行多次解析,保证一个方法只会被解析一次,线程安全
result = serviceMethodCache.get(method);
if (result == null)
//解析方法中的注解参数
result = ServiceMethod.parseAnnotations(this, method);
//将解析的结果放到缓存中,下次调用方法时直接从缓存中取,而不用重新解析注解
serviceMethodCache.put(method, result);
return result;
2.2.2 调用ServiceMethod.parseAnnotations()方法解析方法注解信息
//如果缓存中没有method方法的ServiceMethod对象,则调用ServiceMethod的parseAnnotations方法进行注解解析
/**
* 解析方法的注解信息,封装成一个ServiceMethod对象
*/
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
//方法不能没有返回值
if (returnType == void.class)
throw methodError(method, "Service methods cannot return void.");
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
ServiceMethod.parseAnnotations(retrofit, method)方法两步走:
(1)调用RequestFactory.parseAnnotations方法解析方法的注解,构建RequestFactory对象
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//RequestFactory.parseAnnotations()方法,调用了Builder()生成一个RequestFactory对象
static RequestFactory parseAnnotations(Retrofit retrofit, Method method)
return new Builder(retrofit, method).build();
//RequestFactory.build()方法,在构建RequestFactory实例时,对方法进行了解析
RequestFactory build()
//1. 解析方法的注解,如@FormUrlEncoded @POST @Multipart等
for (Annotation annotation : methodAnnotations) //遍历方法的注解信息
parseMethodAnnotation(annotation);
//...对注解信息进行合法性校验,若不符合规格,抛出相应错误
int parameterCount = parameterAnnotationsArray.length;//获取方法中注解参数个数
parameterHandlers = new ParameterHandler<?>[parameterCount];
//2. 解析方法中参数注解,如@Field @Header @Query @Url @Part @Body等
for (int p = 0; p < parameterCount; p++)
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
//...对注解参数的合法性进行校验,若不符合规格,抛出相应错误
return new RequestFactory(this);//返回RequestFactory实例
(2)调用ServiceMethod实现类HttpService.parseAnnotations方法
//HttpServiceMethod.parseAnnotations()方法
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);//构建CallAdapter实例
Type responseType = callAdapter.responseType();//根据callAdapter实例得到接口的返回值类型
//由于Retrofit对返回值进行了封装,所以不应该是okHttp.Response或是其父类的返回类型
if (responseType == Response.class || responseType == okhttp3.Response.class)
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType))
throw methodError(method, "HEAD method must use Void as response type.");
//得到返回值转换器Converter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//返回代表方法的HttpServiceMethod对象,包含callAdapter\\Converter
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
1)CallAdapter起作用的地方,通过调用Retrofit.callAdapter()方法找到相应的CallAdpater,转换想要的类型
/**
* 创建CallAdapter,将返回值类型转换成想要的类型
*/
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method)
Type returnType = method.getGenericReturnType();//获取方法中返回值类型(是个泛型)
Annotation[] annotations = method.getAnnotations();//获取方法的注解
try
//调用Retrofit.callAdapter方法获取到相应的适配器
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
catch (RuntimeException e) // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
2)Converter起作用的地方
//HttpServiceMethod.createResponseConverter方法,最终将返回值的F类型转换成T类型
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType)
Annotation[] annotations = method.getAnnotations();
try
//调用Retrofit.responseBodyConverter方法获取相应的Converter转换器
return retrofit.responseBodyConverter(responseType, annotations);
catch (RuntimeException e) // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations)
return nextResponseBodyConverter(null, type, annotations);
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations)
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++)
//从converterFactories工厂中找到相应的适配器
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null)
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
Retrofit.loadServiceMethod(Method method)会调用ServiceMethod.parseAnnotations(retrofit, method)方法,ServiceMethod是个抽象类,它的实现类是HttpServiceMethod,HttpServiceMethod主要是将接口方法调用转换成Http方法调用。ServiceMethod的parseAnnotations方法又会调用实现类HttpServiceMethod的parseAnnotations(retrofit, method, requestFactory)方法,其中requestFactory是由RequestFactory.parseAnnotations(retrofit, method)构建的对象,主要对方法中的注解进行解析。
3、Retrofit的OkHttpCall执行execute方法
1中的第五步,执行Call.execute()方法的真正实现如下:
//OkHttpCall的execute()方法
public Response<T> execute() throws IOException
okhttp3.Call call;
synchronized (this)
if (executed) throw new IllegalStateException("Already executed.");//execute()方法只能被执行一次
executed = true;
//...省略错误处理代码
call = rawCall;
if (call == null)
try
//1.构建okhttp3.Call对象
call = rawCall = createRawCall();
catch (IOException | RuntimeException | Error e)
//...错误处理
if (canceled)
call.cancel();
//分两步:1.调用OkHttp.Call的execute()方法,发起网络请求;
//2.调用parseResponse()方法解析返回结果。将OkHttp.Response转换成Retrofit的Response<T>
return parseResponse(call.execute());
3.1 构建okhttp3.Call对象
前面说过Retrofit是对OkHttp封装的框架,内部的网络请求还是由OkHttp发起的,而OkHttp进行网络请求前两步分别是构建Request对象和Call对象,这里也不例外。
//OkHttpCall的createRawCall()方法
private okhttp3.Call createRawCall() throws IOException
//1.requestFactory.create(args)根据请求参数构建okhttp3.Request对象
//2.callFactory.newCall(Request)根据request对象构建okhttp3.Call对象
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null)
throw new NullPointerException("Call.Factory returned null.");
return call;
//第一步:根据接口方法中的参数调用RequestFactory.create()方法构建okhttp3.Request对象
okhttp3.Request create(Object[] args) throws IOException
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
if (argumentCount != handlers.length)
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);//构建RequestBuilder对象
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++)
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();//利用Request.Builder的build()方法构建出Request对象
//第二步:调用OkHttpClient.newCall(Request)方法构建Call对象,Call对象的实现类是RealCall
@Override public Call newCall(Request request)
return RealCall.newRealCall(this, request, false /* for web socket */);
//最终调用RealCall.newRealCall()方法来构建okhttp3.Call对象实例
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket)
// 发布Call实例到EventListener,这样Call能回调EventListener方法
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
3.2 发起网络请求
Retrofit对Call的实现类是RealCall,所以OkHttpCall中的call.execute()方法最终会调用RealCall.execute()方法。
@Override public Response execute() throws IOException
synchronized (this) //Call对象只能被执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
captureCallStackTrace();//对Call对象调用的栈信息进行追踪记录
timeout.enter();
eventListener.callStart(this);//回调EventListener.start()方法,开始进行网络请求
try
client.dispatcher().executed(this);//执行网络请求
Response result = getResponseWithInterceptorChain();//对结果进行各个拦截器链调用
if (result == null) throw new IOException("Canceled");
return result;
catch (IOException e)
e = timeoutExit(e);
eventListener.callFailed(this, e);//回调EventListener.fail方法,请求网络失败
throw e;
finally
client.dispatcher().finished(this);
3.3 对请求结果解析,转换成泛型真实对象
OkHttpCall.parseResponse(call.execute())方法,将okHttp3.Respose结果转换成Retrofit.Response
//OkHttpCall.parseResponse(okhttp3.Response)方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException
ResponseBody rawBody = rawResponse.body();//获取ResponseBody对象
//只取ResponseBody需要的部分,移除其他信息
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) //如果返回值不在200~300之间,说明请求失败了,如服务拒绝请求,或是服务器关闭了、url地址错误等
try
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
finally
rawBody.close();
if (code == 204 || code == 205)
rawBody.close();
return Response.success(null, rawResponse);
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try
//调用相应的Conveter将okHttp3.Response结果转换成Retrofit.Response结果
T body = responseConverter.convert(catchingBody);
//回调success方法
return Response.success(body, rawResponse);
catch (RuntimeException e)
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
总结:
Retrofit框架是对OkHttp网络请求框架的封装,实际网络请求还是调用OkHttp进行网络请求的,它的请求流程可以归纲成下面这张流程图
它主要的工作是在以下几方面:
1、网络请求参数用注解方式,简单明晰,且方法的注解解析只需进行一次就被放入缓存,下次直接从缓存中取,并不会对运行效率造成很大影响;
2、添加了CallAdapter,对网络返回的参数进行了泛化,和Rxjava能进行无缝连接,用户也可以自己定义相应的CallAdapter。
3、添加了Converter,对网络请求对象和返回结果进行转换,如返回结果okhttp3.Response转换成Retrofit.Response。框架还实现了Gson和xml解析器。
以上是关于Retrofit框架源码解读的主要内容,如果未能解决你的问题,请参考以下文章
深入浅出安卓热门网络框架 OKHttp3 和 Retrofit 原理