基本概念 最近把之前看过的Retrofit的源码翻出来研究一下。
Retrofit现在不像两年前是个新鲜事物,大版本已经到Retrofit2了,越来越多的新项目和开源项目会理所应当地使用OkHttp + Retrofit + RxJava + Gson这一套进行网络请求,这也侧面反映了Retrofit的强大(插一句,这几个库厉害不代表会用就厉害,其实用了就知道,这几个的搭配使用的优势就是傻瓜化 )。优秀的框架在使用和扩展上会越来越简单,同时又会更强大,在我看来Retrofit相对于Volley以及更早的框架就是这样。而这时候只会用是不够的,知其然且知其所以然,才能真正学到本事。
这篇分析基于Retrofit2.2.0。
基本流程 这里就不自己画了,借助stay大神的图,毕竟这张图画的太完美了:
源码分析 还是以官方的示例代码来看:
1 2 3 4 5 public interface GitHubService { @GET ("users/{user}/repos" ) Call<List<Repo>> listRepos(@Path ("user" ) String user); }
这个接口用过Retrofit的都算是很熟了,然后再用Retrofit创建一个接口的实现:
1 2 3 4 5 6 Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/" ) .build(); GitHubService service = retrofit.create(GitHubService.class);
这里是一个明显的建造者模式+外观模式,也算是如今许多开源项目的套路了。然后是进行网络请求了:
1 2 Call<List<Repo>> repos = service.listRepos("octocat" );
官网的示例到此结束,一般情况下使用Retrofit都是这么个套路,最多就是在配置时加上Gson或者RxJava。接下来我们开始分析源码,还是从入口开始,关键点在创建API实例的create(class)
方法,我们看这部分源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(this , args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
这里我刚开始看的时候完全不明白,在查了InvocationHandler
相关的知识之后才了解这里用到了Java的动态代理技术。在这里,就是动态生成我们所写的API接口的实现类,创建一个实例,然后把对方法的调用转发给new出来的InvocationHandler
,在invoke
方法中执行接口实现类的逻辑。 然后我们再看其中的具体逻辑。第一步中源码有注释,如果调用的是Object类的方法(toString这些),那就直接调用。第二步如果是default方法就调用default方法,这个default方法来自Java8,具体见这篇Java8 默认方法 。然后就是关键部分了,因为我们在使用的时候不可能是前两种情况,我们调用的都是我们自己写的接口的方法,接下来这几行代码就是请求的具体过程了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);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; }
在loadServiceMethod
方法里创建了一个ServiceMethod
的实例,并且在中间实现了缓存逻辑。然后再看ServiceMethod
里的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ServiceMethod(Builder<R, T> builder) { this .callFactory = builder.retrofit.callFactory(); this .callAdapter = builder.callAdapter; this .baseUrl = builder.retrofit.baseUrl(); this .responseConverter = builder.responseConverter; this .httpMethod = builder.httpMethod; this .relativeUrl = builder.relativeUrl; this .headers = builder.headers; this .contentType = builder.contentType; this .hasBody = builder.hasBody; this .isFormEncoded = builder.isFormEncoded; this .isMultipart = builder.isMultipart; this .parameterHandlers = builder.parameterHandlers; }
通过ServiceMethod
的构造方法,我们基本能知道这个类的成员变量都有哪些。首先看我们比较眼熟的两个成员变量,responseConverter
和callAdapter
,因为搭配使用过RxJava + Retrofit + Gson的人都知道在创建Retrofit实例的时候是这么写的:
1 2 3 4 5 6 Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
先看 ServiceMethod
里callAdapter
相关的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 { return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { throw methodError(e, "Unable to create call adapter for %s" , returnType); } }
可以看到这个成员变量的callAdapter
还是由Retrofit
来提供,在Retrofit
类内部有这样一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null , returnType, annotations); } public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null" ); checkNotNull(annotations, "annotations == null" ); int start = adapterFactories.indexOf(skipPast) + 1 ; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this ); if (adapter != null ) { return adapter; } } StringBuilder builder = new StringBuilder("Could not locate call adapter for " ) .append(returnType) .append(".\n" ); if (skipPast != null ) { builder.append(" Skipped:" ); for (int i = 0 ; i < start; i++) { builder.append("\n * " ).append(adapterFactories.get(i).getClass().getName()); } builder.append('\n' ); } builder.append(" Tried:" ); for (int i = start, count = adapterFactories.size(); i < count; i++) { builder.append("\n * " ).append(adapterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }
在这里会遍历一个CallAdapter.Factory
的列表,直到找到可用的工厂,我们在构建Retrofit
时传入的RxJavaCallAdapterFactory
就是在这里要使用的。然后再看responseConverter
这个成员变量的相关方法:
1 2 3 4 5 6 7 8 9 private Converter<ResponseBody, T> createResponseConverter() { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { throw methodError(e, "Unable to create converter for %s" , responseType); } }
看起来还是由Retrofit
来提供:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { return nextResponseBodyConverter(null , type, annotations); } public <T> Converter<ResponseBody, T> nextResponseBodyConverter(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++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this ); if (converter != null ) { return (Converter<ResponseBody, T>) converter; } } StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for " ) .append(type) .append(".\n" ); if (skipPast != null ) { builder.append(" Skipped:" ); for (int i = 0 ; i < start; i++) { builder.append("\n * " ).append(converterFactories.get(i).getClass().getName()); } builder.append('\n' ); } builder.append(" Tried:" ); for (int i = start, count = converterFactories.size(); i < count; i++) { builder.append("\n * " ).append(converterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }
大体逻辑毫无二致。ServiceMethod
里另外两个比较关键的成员变量分别是callFactory
和parameterHandlers
,callFactory
本质是okhttp3.Call.Factory
,在Retrofit
的构建过程中也可以传入自己实现的okhttp3.Call.Factory
,如果没有,则会默认创建一个OkHttpClient
。再看parameterHandlers
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private ParameterHandler<?> parseParameter( int p, Type parameterType, Annotation[] annotations) { ParameterHandler<?> result = null ; for (Annotation annotation : annotations) { ParameterHandler<?> annotationAction = parseParameterAnnotation( p, parameterType, annotations, annotation); if (annotationAction == null ) { continue ; } if (result != null ) { throw parameterError(p, "Multiple Retrofit annotations found, only one allowed." ); } result = annotationAction; } if (result == null ) { throw parameterError(p, "No Retrofit annotation found." ); } return result; }
因为我们我们在写业务层的API时都是通过注解传入参数的,它的作用就是解析每个参数使用的注解类型并进行处理。到这里ServiceMethod
这部分基本解释结束。在这个类里面,核心的就是三个工厂:okhttp3.Call.Factory
、CallAdapter.Factory
和Converter.Factory
,核心的模块全部交给工厂来做,外界可以通过传入自己的工厂实现对流程的完全控制,真正做到了高内聚低耦合(虽然在我看来okhttp3.Call.Factory
还是有点强依赖于OkHttp )。ServiceMethod
看完了,再看OkHttpCall
。它实现了retrofit2.Call
接口,execute()
和enqueue(callback)
这两种请求都是在这里来做。先看execute()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 @Override public Response<T> execute () throws IOException { okhttp3.Call call; synchronized (this ) { if (executed) throw new IllegalStateException("Already executed." ); executed = true ; if (creationFailure != null ) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else { throw (RuntimeException) creationFailure; } } call = rawCall; if (call == null ) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); } private okhttp3.Call createRawCall () throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null ) { throw new NullPointerException("Call.Factory returned null." ); } return call; } 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 ) { try { 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); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; } }
execute()
方法里的代码并不多,其实就是一个构造请求、请求网络、解析返回数据的过程。在createRawCall()
的时候就可以用serviceMethod
的callFactory
来构造具体请求。在处理返回数据的时候responseConverter
也就派上了用场。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 @Override public void enqueue (final Callback<T> callback) { if (callback == null ) throw new NullPointerException("callback == null" ); okhttp3.Call call; Throwable failure; synchronized (this ) { if (executed) throw new IllegalStateException("Already executed." ); executed = true ; call = rawCall; failure = creationFailure; if (call == null && failure == null ) { try { call = rawCall = createRawCall(); } catch (Throwable t) { failure = creationFailure = t; } } } if (failure != null ) { callback.onFailure(this , failure); return ; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { 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(); } } }); }
代码看起来长,但是大体逻辑与同步请求没有本质区别,只是在异步的callback里进行返回数据的处理。到这里,一次完整的请求就完成了。
总结 其实Retrofit的诱人之处完全不止于此,许多人使用Retrofit都是冲着RxJavaCallAdapterFactory
和GsonConverterFactory
去的,如果有更深的兴趣,可以读一下这些Factory
的具体实现的代码,因为不只有RxJavaCallAdapterFactory
和GsonConverterFactory
这两个,还有Java8CallAdapterFactory
和JacksonConverterFactory
这些工厂。当然我们也可以根据需求写我们自己的工厂。另外Retrofit里的CallAdapter
默认使用的是OkHttp,我们完全也可以用其他的框架替代OkHttp。Retrofit除了充足的扩展性,另一个就是它对设计模式的灵活运用,包括刚开始提到的门面模式,建造者模式,还有工厂模式,另外在这些工厂的具体实现里还有策略模式和装饰模式。具体可以看这一篇Retrofit分析-经典设计模式案例 。总之,Retrofit确实是一个优质的网络封装库,而且它用不多的代码却实现了模块的完全解耦和充分的扩展性,源码很值得一读。