去年10月,之前看的Retrofit源码,原来一直没有发表…
Retrofit是Github上面squre组织开发的一个类型安全的Http客户端,它可以在Java和Android上面使用。Retrofit将描述请求的接口转换为对象,然后再由该对象去请求后台。Retrofit将请求对象化了。目前已经发布了2.0beta版本。
Retrofit主要有以下功能特点
这是一个简单的例子,访问httpbin网站。也可以看完整的Retrofit Demo
首先声明一个java接口
public interface HttpbinService {
@GET("/get?arg1=hello")
Call<HttpbinRequest> testGet();
}
使用方式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://httpbin.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
HttpbinService httpbinService = retrofit.create(HttpbinService.class);
使用httpbinService获取一个Call,用来请求HTTP服务器。
Call<HttpbinRequest> call = httpbinService.testGet();
因为接口返回的应该是一个Call,用来请求后台HTPP服务器,所以我们在声明接口的似乎,返回参数应该是Call
Retrofit可以分为注解解析(Request生成),请求执行,请求回调(异步处理),响应体转化几个部分。其中请求执行与请求回调可以算作一个部分,并且请求回调也可以没有,Call有直接执行的接口execute。
这里面第三部与第四步是可以合在一起的,但是目前Retrofit提供的默认代码中,会通过Call,加入Callback,用户可以在Callback中处理结果。
注解(Annotation)是Retrofit预先定义的注解,包括Http的各个部分,比如POST、GET、Query、QueryMap、Field等等。
其中生成Call的部分可以看下面关于这个适配器的类图。
首先是整个项目的类图
对于Retrofit项目中CallAdapter用着适配器模式也挺巧的,通过适配器将Callback回调接口运行在UI线程。下面时有关CallAdapter,Call,Callback的类图,其中也是连续用了两次代理模式。
ExecutorCallback代理的是用户自定义的Callback。通过这种方式让OkHttpCall去执行Call,让ExecutorCallback将用户自定义的Callback运行在指定线程上。
在Retrofit开源库中,Retrofit类是用户最基础的访问入口。然后Converter部分是由用户自己扩展的,而Paraser部分的相关类RequestBuilder,RequestFactory等则主要是负责解析接口并且生成Request,而Call,CallAdapter等主要是负责底层的Http请求,以及请求后线程转换。
Retrofit类是包含了一个构造器Retrofit.Builder,由Builder指定Retrofit的相关参数,创建一个新的Retrofit。Retrofit中包含了很多重要的成员变量,而这些成员变量都是可以自设置的。
Retrofit包含以下成员变量:
- baseUrl: Http请求的基础url,类型是BaseUrl,包含了url函数返回HttpUrl(OkHttp的类),由Retrofit.Builder.baseUrl设置。
- client:OkHttp库的OkHttpClient类型。由Builder的client函数设置,默认为OkHttpClient()
。
- methodHandlerCache:Map类型,MethodHandler的缓存,从接口中解析出来,放在这个map里面。
- converterFactories:List类型,包含了很多converter的创建工厂,用户可以通过Builder的addConverterFactory来添加。默认添加了BuiltInConverters。
- callbackExecutor:回调函数的执行器,也就是回调函数执行的线程,Android中默认为MainThreadExecutor。
- adapterFactories:List类型,包含了CallAdapter.Factory,用户可以通过Builder的addCallAdapterFactory来添加。Android中默认添加了ExecutorCallAdapterFactory。使用callbackExecutor作为Executor。
- validateEagerly:这个是设置的在创建动态代理对象之前,是否提前解析接口Method,创建MethodHandler并添加到Cache中。
Retrofit重要方法:
- create(final Class service):T
这个是一个public模版方法,用户可以通过这个方法,传入接口Class(T),获得接口Class Http请求的动态代理对象。这是该开源库的主入口,这个函数先验证接口以及其方法,然后创建一个匿名InvocationHandler,在匿名InvocationHandler的invoke中首先去掉Object以及Platform默认的方法,然后调用loadMethodHandler解析对应的方法(接口方法),创建MethodHandler加入到methodHandlerCache中,得到MethodHandler,最后调用MethodHandler的invoke方法得到返回结果(接口方法的返回类型)。动态代理请见Java动态代理
- loadMethodHandler(Method method):MethodHandler
MethodHandler是retrofit中连接了解析部分,执行部分,转换部分的一个关键的中间类。不过MethodHandler的代码量很少。它可以说是连接各个部分的桥梁,也是接口方法的描述类。它有包含了retrofit,requestFactory,callAdapter,responseConverter成员变量。主要方法如下
Object invoke(Object... args) {
return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args));
}
这两个类别都是在Converter文件下。Converter是接口,Factory抽象类,很简短。
public interface Converter<F, T> {
T convert(F value) throws IOException;
abstract class Factory {
// 返回将ResponseBody转化为Type具体的对象的Converter
public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {
return null;
}
//返回将函数Body参数转化为RequestBody的Converter
public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
return null;
}
}
}
Factory主要是负责生成两种Converter。Retrofit实现了一个简单的BuiltInConverters。
这是Retrofit的框架基础接口。它是Retrofit的发送请求给服务器并且返回响应体的调用。每个Call都有自己的HTTP请求和相匹配的响应。
它有如下四个接口:
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
void cancel();
Call<T> clone();
这是Retrofit的框架基础接口。CallAdapter是将一个Call适配给另外一个Call的适配器接口。它有以下两个接口:
- responseType 返回请求后,转化的参数Type类型。
Type responseType();
- adapt 适配,将一个Call转换成另外一个Call。
<R> T adapt(Call<R> call);
请求结构的回调接口。在Call的enquene接口中使用 有如下两个方法
void onResponse(Response<T> response, Retrofit retrofit);
void onFailure(Throwable t);
实现了Call接口,但同样是模版类。首先介绍一下OkHttpCall的主要函数:
- createRawCall
private com.squareup.okhttp.Call createRawCall()
根据由requestFactory根据args创建一个Request,然后利用这个Request创建一个okhttp.Call。
private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse) throws IOException
解析okhttp.Response,
1. 首先将body读取出来作为rawBody,然后用OkHttpCall.NoContentResponseBody作为新的Body,创建新的rawResponse。
2. 判断Response.code(),如果不在200范围内,读取rawBody出来,返回一个错误的retrofit的Response。如果code为204或205(没有返回内容),则返回一个body为空的retrofit的Response。
3. 如果code正常,则用OkHttpCall.ExceptionCatchingRequestBody包装一下rawBody, 然后使用responseConverter将包装后的catchingBody转化为具体的返回类型数据。
OkHttpCall是将Request放入到okhttp的Call里面执行,执行完成后,又将okhttp的Call返回的Response转化为retrofit的Response,在此同时将Body里面的内容,通过converter转化为对应的对象。这个OkHttpCall
这个类是包含了具体返回对象的响应体。里面包含了模版参数T类型的body对象,以及okhttp的Response。
在Retrofit里面创建了Body注解,Filed注解(Field,FieldMap),请求方法注解(DELETE,GET,PATCH,POST,PUT),请求头注解(HEAD,Header,Headers),multipart注解(Part,Multipart,PartMap),接口加码(FormUrlEncoded),Url,Streaming,查询(Query,QueryMap),参数路径(Path),HTTP
这是一个抽象类,只有一个未实现的perform方法。
abstract void perform(RequestBuilder builder, Object value);
但是在RequestBuilderAction类里面有很多RequestBuilderAction的子类,分别对应注解类。Url,Header,Path,Query,QueryMap,Field,FieldMap,Part,PartMap,Body都是在RequestBuilderAction的内部类,并且继承了RequestBuilderAction。RequestBuilder就是将对应注解的值给RequestBuilder。
这是一个okhttp.Request的创建类。负责设置HTTP请求的相关信息,创建Request。它主要有以下方法:
它的构造方法如下:
RequestBuilder(String method, HttpUrl baseUrl, String relativeUrl, Headers headers, MediaType contentType, boolean hasBody, boolean isFormEncoded, boolean isMultipart)
RequestBuilder就是创建请求。
RequestFactory是创建Request,他有个create方法,
Request create(Object... args) {
参数是接口函数对应的参数值,cerate是创建RequestBuilder,遍历RequestFactory的成员变量requestBuilderActions,设置好RequestBuilder,最后创建Request返回。
这个类主要是接口函数Method的每个注解。入口函数是parse。
static RequestFactory parse(Method method, Type responseType, Retrofit retrofit) { RequestFactoryParser parser = new RequestFactoryParser(method); parser.parseMethodAnnotations(responseType); parser.parseParameters(retrofit); return parser.toRequestFactory(retrofit.baseUrl()); }
先解析方法注解(应用到方法上的注解),比如说FormUrlEncoded,Headers。得到对应的值。
然后再解析方法参数注解(应用到方法参数上的注解),在解析方法参数注解的时候,会生成一个requestBuilderActions数组,对应到每个参数。每个Action都对应了每个函数参数的处理。等到具体函数调用的时候,跟函数具体的参数值对应。也就是RequestFactory与Builder的工作了,这部分是等到运行的时候才能够确定的。
BuiltInConverters 继承自Converter.Factory,返回的responseConverter是OkHttpResponseBodyConverter或VoidConverter,也就是接口方法返回的职能是OkHttp的ResponseBody,或者Void。
返回的requestConverter是OkHttpRequestBodyConverter,接口方法的参数中如果使用Body,那Body也只能是OkHttp的RequestBody。
VoidConverter: 将OkHttp的ResponseBody转化为Void。
OkHttpResponseBodyConverter:将OkHttp的ResponseBody转化为OkHttp的ResponseBody。如果是Streaming标记的接口的话,利用Utils.readBodyToBytesIfNecessary缓冲整个body。
OkHttpRequestBodyConverter:将OkHttp的RequestBody转化为OkHttp的RequestBody。
一个Executor,通过android Handler将Runnable执行在UI线程中。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
这是Retrofit中的一个工具类,里面包含了很多范型的检查、操作。另外以及一些基本的工具性的功能。下面是它里面的函数:
checkNotNull
<T> T checkNotNull(T object, String message)
检查非空,如果是null,则抛出NullPointerException,内容提示为message。
closeQuietly
static void closeQuietly(Closeable closeable)
静默地关闭Closeable对象。不会抛出异常
isAnnotationPresent
static boolean isAnnotationPresent(Annotation[] annotations,Class<? extends Annotation> cls)
判断cls是否是annotations里面的一个实例。如果在则返回true。
readBodyToBytesIfNecessary
static ResponseBody readBodyToBytesIfNecessary(final ResponseBody body) throws IOException
如果body非null的话,把整个body读取出来(读取到buffer),返回再返回一个ResponseBody。
validateServiceInterface
static <T> void validateServiceInterface(Class<T> service)
验证接口是否有效,这个接口就是用户自定义的接口。如果不是接口,或者里面没有任何函数,则抛出IllegalArgumentException异常。
getSingleParameterUpperBound
public static Type getSingleParameterUpperBound(ParameterizedType type)
该函数获取type的单个模版参数的上届。如果type有多个类型,函数会抛出异常,如果模版参数不是WildcardType,则直接返回模版参数类型
hasUnresolvableType
public static boolean hasUnresolvableType(Type type)
判断是否有不能分解的类型,比如有TypeVariable,WildcardType等
getRawType
public static Class<?> getRawType(Type type)
这个方法是从Gson里面截取的,获取type的实际类型。
methodError
static RuntimeException methodError(Method method, String message, Object... args)
static RuntimeException methodError(Throwable cause, Method method, String message,Object... args)
两个重载函数,抛出方法错误异常
getCallResponseType
static Type getCallResponseType(Type returnType)
获取返回Call的返回类型,必须是模版参数类型,并且Call的模版参数不能是retrofit.Response.class。返回getSingleParameterUpperBound(returnType)
Retrofit是很适合扩展的,里面设计的Call,以及Converter就是为了方便扩展使用。
Retrofit提供的默认的Converter只会返回ResponseBody,如果我们想要返回具体的Object,我们可以使用另外的第三方包,并且在创建Retrofit的时候添加对应的ConverterFactory。这里有6个序列化第三方库:
retrofit也可以与Rxjava联合起来使用,之前的版本使用范例可以参考http://randomdotnext.com/retrofit-rxjava/
正在开发中,主要是通过扩展CallAdapter,将之前Call,转换为rxjava需要的Observable
Retrofit整体框架的代码并不多,主要是围绕着converter,CallAdapter设计的整个框架。花了两天时间耐耐心心地把代码也是挺有收获。Retrofit用到的基本技术是动态代理,Java注解,Java范型。另外如果对设计模式很熟悉的话,读起来感觉就会很简单。整个架构设计的非常好。