【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
1.开发中一个常见网络请求过程
url,参数---> request ---> 转化成Http协议 -->请求执行 ---> 返回结果--> 转化成response ---> response转化成我们的对象
只有头和尾是我们日常开发进行自定义的,中间的其他过程都是网络框架进行的。
2.Retrofit做的事情
- 1.url,参数Retrofit主要采用接口+注解方式
- 2.中间网络请求框架采用动态代理去使用某个框架
- 3.response转化成我们的对象采用adapter模式进行适配
3.Retrofit的实现过程
1)toRequest,url,参数Retrofit主要采用接口+注解方式
我们以一个简单的POST请求为例
@POST("ssoService/v1/logoutCTGT")
Call<BaseResponseBean> logout(@Body LogoutRequest logoutRequest);
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
String value() default "";
}
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Body {
}
<u>注解知识点解析</u>
-
注解的定义
- @Documented
Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。
- @Target(METHOD)
注释可能出现在Java程序中的语法位置,TYPE,FIELD,METHOD,PARAMETER等
- @Retention(RUNTIME)
描述保留注释的各种策略,SOURCE(源码期,编译的时候会被忽略),CLASS(会被编译到类文件中,但是JVM中没有),RUNTIME(各个阶段都存在)
-
注解的获取(ServiceMethod.Builder类)
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
获取注解的方法
this.methodAnnotations = method.getAnnotations();
this.parameterAnnotationsArray = method.getParameterAnnotations();
注解获取相对还是比较简单的,Method方法可以直接获取各种注解,一个是方法上面的注解,一个是参数上的注解
- Retrofit对于获取到的注解的处理(ServiceMethod.Builder.build())
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
......
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
注解处理后转化成相关属性
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
然后在ServiceMethod.toRequest方法里转换成 Request
Request toRequest(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
以上分析了注解到toRequest,接下去我们分析下代码的调用过程
同步请求过程
OkHttpCall.execute()->OkHttpCall.createRawCall()->serviceMethod.toRequest()
异步过程
OkHttpCall.enqueue()->OkHttpCall.createRawCall()->serviceMethod.toRequest()
2)toResponse
优先解析toResponse的使用,可以方便我们反推Retrofit如何使用动态代理进行网络框架的调用
相比toRequest,toResponse则简单很多,日常工作当中我们也是经常使用Gson进行结果的转化,我们通过转化器的添加,以及转化的调用流程对toResponse进行一次分析
- 我们先来下转化成我们自己的对象的方法是什么时候添加的
public static <T> T createJsonApi(@Url String baseUrl, Class<T> service) {
if (!checkUrl(retrofitRxJson, baseUrl)) {
retrofitRxJson = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
}
return retrofitRxJson.create(service);
}
.addConverterFactory(GsonConverterFactory.create())
采用Gson把平台返回的内容转化成我们的对象
public class BaseResponseBean<T> {
public Integer type;
public String code;
public String msg;
public T data;
}
- toResponse整个调用过程
- 同步请求
OkHttpCall.excute()-> OkHttpCall.parseResponse()->serviceMethod.toResponse()->serviceMethod.responseConverter.convert()
- 异步请求
OkHttpCall.enqueue()-> hik.lib.okhttp3.Callback.onResponse()->OkHttpCall.parseResponse()->serviceMethod.toResponse()->serviceMethod.responseConverter.convert()
- responseConverter的初始化
ServiceMehtond.Builder.build()->ServiceMehtond.Builder.createResponseConverter()->retrofit.responseBodyConverter()-> retrofit.nextResponseBodyConverter()
<u>这里有个比较好的设计,看代码</u>
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++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
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());
}
<font color="Hotpink"><u>如果返回转换的类型有多个,会根据接口的返回类型进行匹配</u></font>
3)动态代理进行网络框架的使用
我们分析了toRequest()与toResponse(),以及从OkHttpCall网络请求调用两个方法的过程,接下去我们分析动态代理如何调用OkHttpCall里的execute()与enqueue()
我们在使用的时候都是定义接口,但是并没有定义实现类,这里就是使用动态代理方式实现了接口的实现类
##这里有个要注意的地方******************* <u>接口返回的是一个对网络请求进行了封装的对象,并没有进行网络请求</u>
- 动态代理的创建
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, @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);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
从代码来说,动态代理是比较简单的。
<u>动态代理知识点解析</u>
动态代理(dynamic proxy) 利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throws IllegalArgumentException
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
<u>结合我们Retrofit.create方法以及动态代理的知识,也就是我们接口里的所有方法最后都是调用</u>
serviceMethod.callAdapter.adapt(okHttpCall);
这里返回了一个包裹OkHttpCall的对象
这里又有一个知识点
Retrofit
final hik.lib.okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
adapterFactories 返回的对象到底是RxJava2CallAdapterFactory,还是默认的DefaultCallAdapterFactory
我们看下serviceMethod中callAdapter属性的初始化
ServiceMethod.Builder.buid()->ServiceMethod.Builder.createCallAdapter->retrofit.callAdapter->retrofit.nextCallAdapter
上代码
public CallAdapter<?, ?> nextCallAdapter(@Nullable 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());
}
<font color="Hotpink"><u>最后是根据接口的返回类型去匹配使用那个AdapterFactory</u></font>
- 接下去我们看下AdaperFactory的实现
我们先看默认的一个DefaultCallAdapterFactory的实现
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
};
}
}
直接返回的是OkHttpCall 所以网络请求是 execute,enqueue。
如果是RxJava2CallAdapter 则返回的是Observable,然后通过RXJava方法进行网络请求调用,上代码
public static void asyHttpRequest(Observable observable , BaseNetCallback netCallback){
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(new BaseNetObserver<>(netCallback));
}
设置执行的线程,监听结果的线程,然后发起信号执行
我们在看下信号执行里的代码
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
到这里的话我们基本已经了解了Retrofit2 整个代码的过程了
####4.Retrofit的代码总结 Retrofit 主要的代码实现
-
OKHttpCall 主要是网络请求实际实现的地方,主要有
- execute
- enqueue
- createRawCall
-
ServiceMethod
- toRequest
- toResponse
- Builder.build()
-
Retrofit
- create
- nextCallAdapter
- nextResponseBodyConverter
来源:oschina
链接:https://my.oschina.net/u/2264711/blog/3143724