亲宝软件园·资讯

展开

【Android】Retrofit源码学习

y4ngyy 人气:2
## 使用Retrofit的流程 1. 通过Builder创建Retrofit对象: ```java Retrofit retrofit = new Retrofit.Builder().baseUrl("").addConverterFactory().build(); ``` 2. 用Java注解描述API ```java public interface MyApi { @GET("/api") Call getData(); } ``` 3. 通过retrofit创建api对象,并建立Call对象 ```java MyApi api = retrofit.create(MyApi.class); Call call = api.getData(); ``` 4. 通过Call对象获取数据,`enqueue()`方法发送异步请求,同步方式则使用`execute()`方法 ```java call.enqueue(new Callback() { @Override public void onResponse(Response author) { System.out.println("name: " + author.getName()); } @Override public void onFailure(Throwable t) { } }); ``` ## 原理解析 Retrofit所做的事情:将Java接口翻译成HTTP请求,然后用OkHttp去发送请求。 Retrofit使用**动态代理**实现了这件事 ### 动态代理 动态代理可以在不实现相同接口的proxy的情况下,对相关方法进行代理。 Java可以通过Proxy类实现代理模式,而其中的`newProxyInstance() `方法可以实现动态代理。通过实现InvocationHandler接口来定义代理动作。 - `Proxy.newProxyInstance(ClassLoader, Class<?>[] interfaces,InvocationHandler)` InvocationHandler的接口定义如下: ```java public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } ``` 参数含义: - proxy:代理对象 - method: 代理方法 - args: 方法的参数 实现`invoke()`方法来进行代理: ```java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // do something method.invoke(target, args); // do something } ``` 这样便能够成功对target方法进行代理,动态代理生成的代理类的名字为**包名+$Proxy+id序号** #### 请求流程分析 回到使用方法,一开始要使用`create()`生成API的对象 ```java MyApi api = retrofit.create(MyApi.class); ``` 这里看下`create()`的源码: ```java 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 { // 如果是Object的方法则直接调用 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } // 兼容Java8,Android平台不会调用, 确认平台的方法是通过反射机制判断类的加载信息 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } // 主要方法,返回ServiceMethod对象 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } }); } ``` create使用了动态代理的方法,返回了`Proxy.newProxyInstance()`动态代理对象 所以`api`对象为动态代理对象,不是真正的实现接口产生的对象。当api对象调用`getData()`方法时会被动态代理拦截,然后调用InvocationHandler对象中的`invoke()`方法。 然后Retrofit通过反射获取到`getData()`方法的注解信息,配合`invoke()`的args参数,创建一个**ServiceMethod**对象 ServiceMethod传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api的域名、path、http请求方法、请求头、body等等。最后返回一个Call对象。 ```java 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); // 放入Cache中 } } return result; } ``` 跟进`ServiceMethod.parseAnnotation()`: ```java static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) { // 解析注解为HTTP请求的相关信息 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) { //API接口方法返回值不能为void throw methodError(method, "Service methods cannot return void."); } return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } ``` 这里构建了一个`RequestFactory`对象,解析了接口中关于Http协议的相关信息,具体解析方法就是拿到Method的Annotation后`instansof`比较确定 ```java RequestFactory(Builder builder) { method = builder.method; baseUrl = builder.retrofit.baseUrl; httpMethod = builder.httpMethod; relativeUrl = builder.relativeUrl; headers = builder.headers; contentType = builder.contentType; hasBody = builder.hasBody; isFormEncoded = builder.isFormEncoded; isMultipart = builder.isMultipart; parameterHandlers = builder.parameterHandlers; isKotlinSuspendFunction = builder.isKotlinSuspendFunction; } ``` 解析完后使用`HttpServiceMethod.parseAnnotations()`最后生成HttpServiceMethod对象 ```java static HttpServiceMethod parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; // kotlin支持,先忽略 boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); // 方法的注解 @GET @POST @DELETE等 Type adapterType; // ...这里有一段关于Kotlin支持的代码,adapterType adapterType = method.getGenericReturnType(); // 接口方法的返回类型,一般为Call CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); if (responseType == okhttp3.Response.class) { throw methodError(method, "'" + getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } if (responseType == Response.class) { throw methodError(method, "Response must include generic type (e.g., Response)"); } // HEAD请求没有Response Body if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) { throw methodError(method, "HEAD method must use Void as response type."); } // 设置Response的解析,可以是json解析 Converter responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; // 这里若是没有自定则默认为OkHttpClient if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 不使用Kotlin就关注这里就行了 } // ...关于Kotlin的return } ``` 最后返回了HttpServiceMethod的继承类`CallAdapted`,其中存放着`RequestFactory`、`Converter`、`CallFactory` 然后我们返回来看这段代码 ```java return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); ``` 这里调用的`invoke`方法来为HttpServiceMethod中的`invoke`方法: ```java @Override final @Nullable ReturnT invoke(Object[] args) { Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } // CallAdapted中 @Override protected ReturnT adapt(Call call, Object[] args) { return callAdapter.adapt(call); } ``` 这里的OKHttpCall为Okhttp3.Call的封装类,并实现了Call的相关方法`enqueue`、`execute`。 这里最后使用的`adapt`方法调用了Retrofit对象中的`callAdapter.adapt()`来对`Call`对象进行了适配。 若是开始初始化Retrofit对象时没有设置CallAdapter,则回默认使用`Call`,api接口定义时方法的返回类型只能是`Call` 所以便能解释如下代码: ```java Call call = api.getData(); ``` api对象为一个动态代理对象,当执行`getData()`时进入动态代理函数,在InvocationHandler的invoke函数最后调用了`HttpServiceMethod.invoke(args)`,返回了一个`Call`对象。 #### 响应流程分析 Retrofit使用中最后调用自定义的API接口方法返回了`Call`对象,这个对象实际上是Retrofit自己封装的OkHttpCall对象,随后我们使用`enqueue`方法发出异步请求 ```java call.enqueue(new CallBack() { @Override public void onResponse(Call call, Response response) { //... on response } @Override public void onFailure(Call call, Throwable t) { //... on response } }) ``` 跟进`OkHttpCall.enqueue`的源码: ```java @Override public void enqueue(final Callback callback) { Objects.requireNonNull(callback, "callback == null"); // callback不能为null okhttp3.Call call; // okhttp3的Call对象 Throwable failure; synchronized (this) { // 线程安全 if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; // rawCall为OkHttpCall保存的Okttp3的Call对象 failure = creationFailure; if (call == null && failure == null) { try { // createRawCall中使用callFactory.newCall(requestFactory.create(args)) // 实际上就是OkHttpClient.newCall(OkHttp3.Request) // 返回了OkHttp3.Call对象 call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } // 使用okhttp3.Call的enqueue方法 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response response; try { // 这里使用了Converter来解析Response // 将Okhttp3.Response对象解析成Retrofit封装的Response对象 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { // 调用传进来的回调 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } // 请求失败则进入callback的OnFailure方法 private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } }); } ``` 其中`parseResponse()`方法: ```java Response parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // 将Response Body 和 ResponseHeader 分开 // 之后再对Body进行处理 rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); // HTTP 状态码 // 响应不成功 if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } // 响应无内容,填入null if (code == 204 || code == 205) { rawBody.close(); return Response.success(null, rawResponse); } // 保存source的Response Body,在解析失败时可以使用 ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { // 使用responseConverter来解析Body T body = responseConverter.convert(catchingBody); // 将解析好的Body装入Retrofit的Response对象返回 return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; } } ``` 主要的parse过程便是,将Okhttp.Response对象的Body和Header拆开,若请求成功且Body有内容则将Body交给responseConverter取解析成响应对象,装入Retrofit的Response对象中返回。 ## 总结 1. Retrofit的特色:通过使用注解定义API接口的方式声明API,通过注解的解析,将解析得到的信息封装在RequestFactory中,在使用时调用`create()`方法生成Okhttp的Request对象。 2. 通过动态代理的方式,代理用户定义的API接口方法,使其生成封装的OkHttpCall对象 3. 封装okhttp.Call为OkHttpCall,使其能够使用CallAdapter(可以使返回的Call对象适配为其他的对象,如RxJava(没用过)中的对象)和ResponseConverter(支持Gson等解析) 4. 目前只读到这里,还有一些机制没读完 ## 参考文章 https://www.jianshu.com/p/c1a3a881a144 https://segmentfault.com/a/1190000006767113 https://yq.aliyun.com/articles/658544

加载全部内容

相关教程
猜你喜欢
用户评论