retrofit源码

定义接口

//定义接口
public interface GitHubService {
    @GET("users/{user}/repos")
    Observable<List<Repo>> listRepos(@Path("user") String user);
}

下面我们以如下配置作为源码分析

Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(ProtoConverterFactory.create())
.build()

先看看Retrofit实例构建入口:


//Retrofit.java
public Retrofit build() {
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }
    
    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    
    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
    }
    
    // Make a defensive copy of the adapters and add the default Call adapter.
    List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,callbackExecutor, validateEagerly);
}
  • baseUrl必须指定,这个是理所当然的;
  • 然后可以看到如果不着急设置callFactory,则默认直接new OkHttpClient(),可见如果你需要对okhttpclient进行详细的设置,需要构建OkHttpClient对象,然后传入;
  • 接下来是callbackExecutor,这个想一想大概是用来将回调传递到UI线程了,当然这里设计的比较巧妙,利用platform对象,对平台进行判断,判断主要是利用Class.forName("")进行查找,具体代码已经被放到文末,如果是Android平台,会自定义一个Executor对象,并且利用Looper.getMainLooper()实例化一个handler对象,在Executor内部通过handler.post(runnable),ok,整理凭大脑应该能构思出来,暂不贴代码了。
  • 接下来是adapterFactories,这个对象主要用于对Call进行转化,基本上不需要我们自己去自定义。
  • 最后是converterFactories,该对象用于转化数据,例如将返回的responseBody转化为对象等;当然不仅仅是针对返回的数据,还能用于一般备注解的参数的转化例如@Body标识的对象做一些操作,后面遇到源码详细再描述。

Retrofit实例使用:

//获取实例
GitHubService service = retrofit.create(GitHubService.class);

Retrofit.java

public <T> T create(final Class<T> service) {
    //...
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {
        @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //... 
            //将每一个接口中定义的method包装成ServiceMethod对象
            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对象
    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;
  }

ServiceMethod.java

public ServiceMethod build() {
    callAdapter = createCallAdapter();
    responseType = callAdapter.responseType();
    //...
    responseConverter = createResponseConverter();
        
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }
    //...
    return new ServiceMethod<>(this);
}

首先通过调用createCallAdapter方法

CallAdapter<T, R> callAdapter = createCallAdapter() = RxJava2CallAdapterFactory.get(Type returnType, Annotation[] annotations, Retrofit.this)
      
//RxJava2CallAdapterFactory.java
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
    
    if (rawType == Completable.class) {
        // Completable is not parameterized (which is what the rest of this method deals with) so it
        // can only be created with a single configuration.
        return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false, false, true);
    }
//......
}

再调用callAdapter.responseType()

//RxJava2CallAdapter.java
//这个responseType是构造参数传递进来的,也就是上面传递的Void.class
@Override public Type responseType() {
    return responseType;
}

调用createResponseConverter()方法,最终会调用

ProtoConverterFactory.responseBodyConverter(Type type, Annotation[] annotations, Retrofit.this)

返回的实际类型是ProtoResponseBodyConverter

继续下来就是对修饰方法的注解进行解析了,然后使对修饰参数的注解进行解析会得到很多ParameterHandler对象(这个对象由parseParameter()方法创建),该对象在toRequest()构造Request的时候回调用其apply方法

对上面一小段进行下总结:我们知道ServiceMethod主要用于将我们接口中的方法转化为一个Request对象,于是根据我们的接口返回值确定了responseConverter,解析我们方法上的注解拿到初步的url,解析我们参数上的注解构建RequestBody所需要的各种信息,最终调用toRequest的方法完成Request的构建

到这里ServiceMethod的构建就分析完了,下面我们看OkHttpCall的构建

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}

可以看到构造函数很简单,就赋下值。那我们继续看最后一行关键代码

serviceMethod.callAdapter.adapt(okHttpCall);

经过上面代码的分析,我们知道callAdapter的实例类型是RxJava2CallAdapter,那我们就看RxJava2CallAdapteradapt这个方法

@Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
       ? new CallEnqueueObservable<>(call)
       : new CallExecuteObservable<>(call);
    
    Observable<?> observable;
    if (isResult) {
        observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
        observable = new BodyObservable<>(responseObservable);
    } else {
        observable = responseObservable;
    }
    
    if (scheduler != null) {
        observable = observable.subscribeOn(scheduler);
    }
    
    if (isFlowable) {
        return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
        return observable.singleOrError();
    }
    if (isMaybe) {
        return observable.singleElement();
    }
    if (isCompletable) {
        return observable.ignoreElements();
    }
    return observable;
}

可以看到,同步就构建CallEnqueueObservable,不需要同步就构建CallExecuteObservable

当返回的Observable订阅事件后,就会执行okHttpCall.execute()方法(这里的流程没有分析,因为要涉及到Rxjava2,还没有学习)

//OkHttpCall.java
@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    
    synchronized (this) {     
        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());
}

//OkHttpCall.java
private okhttp3.Call createRawCall() throws IOException {
    //这里的args是调用接口方法调用的参数数组,到这里就完成了Request的构建
    Request request = serviceMethod.toRequest(args);
    //通过Request对象构造Call对象
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    return call;
}

//OkHttpClient.java
@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
}


//OkHttpCall.java
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    
    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
       .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
       .build();
    
    int code = rawResponse.code();
    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();
        }
    }
    
    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) {
        // If the underlying source threw an exception, propagate that rather than indicating it was
        // a runtime exception.
        catchingBody.throwIfCaught();
        throw e;
    }
}

//Retrofit.java
R toResponse(ResponseBody body) throws IOException {
    //我们知道responseConverter的实例是ProtoResponseBodyConverter对象
    return responseConverter.convert(body);
}

//CallExecuteObservable.java
observer.onNext(response);

那么总结一下

  • 首先构造retrofit,几个核心的参数呢,主要就是baseurl,callFactory(默认okhttpclient),converterFactories,adapterFactories,excallbackExecutor。

  • 然后通过create方法拿到接口的实现类,这里利用Java的Proxy类完成动态代理的相关代理

  • 在invoke方法内部,拿到我们所声明的注解以及实参等,构造ServiceMethod,ServiceMethod中解析了大量的信息,最痛可以通过toRequest构造出okhttp3.Request对象。有了okhttp3.Request对象就可以很自然的构建出okhttp3.call,最后calladapter对Call进行装饰返回。

  • 拿到Call就可以执行enqueue或者execute方法了

最后来整个thrift的结构图

发表评论

电子邮件地址不会被公开。 必填项已用*标注

返回主页看更多
狠狠的抽打博主 支付宝 扫一扫