【Android】Retrofit源码学习

使用Retrofit的流程

  1. 通过Builder创建Retrofit对象:

    Retrofit retrofit = new Retrofit.Builder().baseUrl("").addConverterFactory().build();
    
  2. 用Java注解描述API

    public interface MyApi {
        @GET("/api")
        Call<Data> getData();
    }
    
  3. 通过retrofit创建api对象,并建立Call对象

    MyApi api = retrofit.create(MyApi.class);
    Call<Data> call = api.getData();
    
  4. 通过Call对象获取数据,enqueue()方法发送异步请求,同步方式则使用execute()方法

    call.enqueue(new Callback<Data>() {
        @Override
        public void onResponse(Response<ZhuanLanAuthor> 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的接口定义如下:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

参数含义:

  • proxy:代理对象
  • method: 代理方法
  • args: 方法的参数

实现invoke()方法来进行代理:

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
	// do something
    method.invoke(target, args);
    // do something
}

这样便能够成功对target方法进行代理,动态代理生成的代理类的名字为包名+$Proxy+id序号

请求流程分析

回到使用方法,一开始要使用create()生成API的对象

MyApi api = retrofit.create(MyApi.class);

这里看下create()的源码:

  public <T> T create(final Class<T> 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对象。

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():

static <T> ServiceMethod<T> 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比较确定

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对象

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> 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<T>

    CallAdapter<ResponseT, ReturnT> 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<String>)");
    }
    // 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<ResponseBody, ResponseT> 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,其中存放着RequestFactoryConverterCallFactory

然后我们返回来看这段代码

return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

这里调用的invoke方法来为HttpServiceMethod中的invoke方法:

@Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}
// CallAdapted中
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
}

这里的OKHttpCall为Okhttp3.Call的封装类,并实现了Call的相关方法enqueueexecute

这里最后使用的adapt方法调用了Retrofit对象中的callAdapter.adapt()来对Call对象进行了适配。

若是开始初始化Retrofit对象时没有设置CallAdapter,则回默认使用Call<T>,api接口定义时方法的返回类型只能是Call<T>

所以便能解释如下代码:

Call<MyData> call = api.getData();

api对象为一个动态代理对象,当执行getData()时进入动态代理函数,在InvocationHandler的invoke函数最后调用了HttpServiceMethod.invoke(args),返回了一个Call<T>对象。

响应流程分析

Retrofit使用中最后调用自定义的API接口方法返回了Call<T>对象,这个对象实际上是Retrofit自己封装的OkHttpCall对象,随后我们使用enqueue方法发出异步请求

call.enqueue(new CallBack<MyData>() {
    @Override
    public void onResponse(Call<MyData> call, Response<MyData> response) {
    	//... on response    
    }
    @Override
    public void onFailure(Call<MyData> call, Throwable t) {
    	//... on response    
    }
})

跟进OkHttpCall.enqueue的源码:

@Override public void enqueue(final Callback<T> 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<T> 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()方法:

Response<T> 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

posted @ 2020-03-20 11:29  y4ngyy  阅读(324)  评论(0编辑  收藏  举报