Retrofit 原理


一、介绍

Retrofit,是一个网络框架。客户端创建一个Retrofit 实例,建造者设计模式,配置一些基础内容,例如baseUrl地址,CallAdapter工厂,Converter工厂,okhttp3的Call工厂,底层网络访问默认okhttp3网络框架。

Retrofit retrofit = new Retrofit.Builder().baseUrl(HostIp)
              .addConverterFactory(GsonConverterFactory.create())
              .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
              .client(okHttpClient)
              .build();

baseUrl方法,配置服务器Url。client方法,参数实现okhttp3.Call#Factory接口,工厂创建okhttp的RealCall对象,真正的网络请求由它发起。

Retrofit知识结构

Retrofit框架基于动态代理实现,定义一个接口,每一个接口方法描述一个Http请求。

private RestfulApi apiService;

//接口
public interface RestfulApi {
    @POST("login?")
    Call postLogin(@QueryMap Map paramMap);
}

//创建动态代理对象
apiService = retrofit.create(RestfulApi.class);

//调用代理对象方法,创建一个请求
Call call = apiService.postLogin();

//发起请求和回调
call.enqueue(new Callback() {
    @Override
    public void onResponse(Call call, Response response) {
    }

    @Override
    public void onFailure(Call call, Throwable t) {
    }
});

方法注解,@POST,@PUT,@GET,@DELETE,@HEAD,代表请求类型,参数注解,@Query,@QueryMap,@Field,@FieldMap,@Path,@Url,代表请求参数。

@GET请求,使用@Query或@QueryMap,参数拼接在Url路径后面。
@POST请求,使用@Field、@FieldMap和@FormUrlEncoded,参数放在请求体。

根据interface接口,创建动态代理对象,客户端使用该对象,调用接口方法,返回一个Retrofit框架的Call或Rx的Observable。根据Call的同步/异步方式,发起请求,enqueue/execute回调,或者利用Rx的subscribe方法。

CallAdapter工厂,生产适配Call的CallAdapter,调用方法返回类型转换。Convert工厂,生产Response和Request的数据转换器。

Retrofit流程

二、Retrofit 和 Okhttp

Retrofit类的create方法,创建接口的动态代理对象。

public  T create(final Class service) {
    return (T) Proxy.newProxyInstance(service.getClassLoader(), 
        new Class[] { service },  new InvocationHandler() {
            //该对象传入$Proxy0的构造方法中
            private final Platform platform = Platform.get();
            @Override 
            public Object invoke(Object proxy, Method method, Object... args) 
                        throws Throwable {
                ...
                ServiceMethod serviceMethod = loadServiceMethod(method);
                OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
        });
}

调用代理对象的方法时,在InvocationHandler的invoke方法中拦截,根据Method载入一个ServiceMethod对象,以前调用过接口方法的ServiceMethod保存在Cache中,ServiceMethod服务于对应Method。

InvocationHandler的invoke方法Method参数

创建一个实现Retrofit#Call接口的OkhttpCall,callAdapter适配成接口返回对象Call或Rx的Observable,OkhttpCall封装调用方法的ServiceMethod和args参数,内部rawCall,okhttp3的Call类型。

委托者

调用OkhttpCall的enqueue或execute方法时,createRawCall方法,创建rawCall。

private okhttp3.Call createRawCall() throws IOException {
    //解析参数,创建okHttp3#Request
    Request request = serviceMethod.toRequest(args);
    //工厂创建rawCall
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    ...
    return call;
}

ServiceMethod类解析参数数组,转换成一个Http协议的okHttp3#Request请求实体。okhttp3的Call工厂根据Request实体,创建okhttp3#Call,本质是RealCall。

@Override 
public void enqueue(final Callback callback) {
    okhttp3.Call call = rawCall = createRawCall();
    ...//入参是Retrofit的Callback
    call.enqueue(new okhttp3.Callback() {
        @Override 
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
                throws IOException {
            Response response;
            try {
                //转换Response
                response = parseResponse(rawResponse);
            } catch (Throwable e) {
                callback.onFailure(OkHttpCall.this, e);
                return;
            }
            callback.onResponse(OkHttpCall.this, response);
        }
        //同理,onFailure回调
        ...
    });
}

OkhttpCall的enqueue方法,本质是调用内部okhttp3的enqueue方法,在回调对象okhttp3#Callback,调用Retrofit的#Callback方法。将okhttp3的Response转换Retrofit的Response。

Response parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();
    ...
    //NoContentResponseBody和ExceptionCatchingRequestBody都继承ResponseBody。
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
        T body = serviceMethod.toResponse(catchingBody);
        //新建一个Retrofit#Response
        return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
        catchingBody.throwIfCaught();
        throw e;
    }
}

解析okhttp3#Response转换成Retrofit#Response,获取okhttp3.Response的ResponseBody,转换泛型body类型。

转换Response

最终转换的Retrofit#Response包含T类型body和新生成okhttp3#Response,它内部是NoContentResponseBody。

T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
}

转换器解析okhttp3的ResponseBody,配置不同的转换器工厂,Http协议一般使用GsonConverter数据转换器。
在ServiceMethod创建时,初始化responseConvert转换器,根据方法注解和返回实体类型responseType,调用Retrofit的nextResponseBodyConvert方法查找。
遍历工厂列表每一项Factory,调用工厂实现的responseBodyConverter方法,根据返回类型和注解获取匹配的Converter。

public interface Converter {
  T convert(F value) throws IOException;
  //创建Converter的抽象工厂
  abstract class Factory {
    public Converter responseBodyConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }
    public Converter requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }
    public Converter stringConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }
  }
}

将responseBody解析成我们期望的数据,只需要配置相应的工厂即可,如gson,xml,protobuf,需要在gradle中引入他们的jar包。
GsonConverter,负责解析responseBody对象,将json格式转换成用户自定义的实体对象,即interface方法返回Call中的泛型。
将T、okhttp3#Response封装一个新建Retrofit#Response对象。

三、CallAdapter 适配

在invoke方法最后一步,将OkHttpCall进行CallAdapter适配,转换成接口方法调用方定义的Object。

public interface CallAdapter {
    Type responseType();
     T adapt(Call call);
    //创建CallAdapter的工厂
    abstract class Factory {
        public abstract CallAdapter get(Type returnType, Annotation[] annotations,
                    Retrofit retrofit);
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }
        protected static Class getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}

适配目的是接口方法返回对象可以是Retrofit#Call外的其他类型,适应不同的接入框架,如Guava,Java8,RxJava。
通过适配器工厂配置不同的适配器,前面添加Rx的工厂,可以适配Rx返回Observable类型。

CallAdapter工厂列表

初始化时,ExecutorCallAdapterFactory默认工厂。

private final List adapterFactories = new ArrayList<>();

List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

在ServiceMethod创建时,初始化内部CallAdapter。

private CallAdapter createCallAdapter() {
    Type returnType = method.getGenericReturnType();

    Annotation[] annotations = method.getAnnotations();
    try {
        //noinspection unchecked
        return (CallAdapter) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
    }
}

根据方法返回值类型和注解,调用Retrofit的nextCallAdapter方法查找。

public CallAdapter nextCallAdapter(...) {
    ..
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
        //每个工厂都实现了get方法,根据此刻调用方法的返回类型。
        //在get方法中会有判断是否匹配,成功匹配,将返回对应是适配器。
        CallAdapter adapter = adapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }
}

每个工厂都实现get方法,遍历工厂列表每一项Factory,根据方法返回类型和注解匹配获取CallAdapter,Call类型匹配默认ExecutorCallAdapterFactory工厂。

@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //返回类型是Call。
    if (getRawType(returnType) != Call.class) {
        return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter>() {
        @Override
        public Type responseType() {
            return responseType;
        }

        @Override
        public  Call adapt(Call call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
        }
    };
}

默认工厂创建的CallAdapter,adapt适配方法,将OkhttpCall再次封装,委派者设计模式,最终返回给接口方法调用者的Call是ExecutorCallbackCall。

@Override 
public void enqueue(final Callback callback) {
    ..//delegate是OkHttpCall。
    delegate.enqueue(new Callback() {//Retrofit#Callback
        @Override public void onResponse(Call call, final Response response) {
            callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                    if (delegate.isCanceled()) {
                        callback.onFailure(...);
                    } else {
                        //callback是用户传入
                        callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                }
            });
        }
        //同理,onFailure回调
        ...
    });
}

接口方法调用者触发Call的enqueue异步方法,网络请求时,内部委派给OkHttpCall。
回调时,MainThreadExecutor的execute方法,通过内部绑定主线程Handler发送Runnable,将Callback执行权转移到主线程。
回调callback接收的Response是在OkHttpCall中已经okhttp3#Response转换过的Retrofit#Response。
适配目的是将Callback发送到主线程。通过它发起网络请求,不用操心线程切换啦。

四、Retrofit 和 Rx

RxJava2CallAdapterFactory工厂,Call适配器是RxJava2CallAdapter,将Retrofit#Call转换成Observable类型。

@Override
public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class rawType = getRawType(returnType);
    ...
    boolean isFlowable = rawType == Flowable.class;
    boolean isSingle = rawType == Single.class;
    boolean isMaybe = rawType == Maybe.class;
    if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
        return null;
    }

    boolean isResult = false;
    boolean isBody = false;
    Type responseType;
    
    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) {

        responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
    } else if (rawObservableType == Result.class) {
        
        responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
        isResult = true;
    } else {
        responseType = observableType;
        isBody = true;
    }
    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
            isSingle, isMaybe, false);
}

工厂get方法,判断匹配类型Observable、isFlowable或者isSingle。

Observable postRxLogin(@QueryMap Map paramMap);

调用interface的postRxLogin方法时,在invoke方法,ServiceMethod内部的callAdapter是RxJava2CallAdapterFactory生产的RxJava2CallAdapter。

屏幕快照 .png
@Override public Object adapt(Call call) {
     //入参call是Retrofit的Call。
    Observable> responseObservable = isAsync
            ? new CallEnqueueObservable<>(call)
            : new CallExecuteObservable<>(call);
    Observable observable;
    if (isResult) {
        observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {//是isBody。选择BodyObservable。
        observable = new BodyObservable<>(responseObservable);
    } else {
        observable = responseObservable;
    }
    if (scheduler != null) {
        observable = observable.subscribeOn(scheduler);
    }
    ...
    return observable;
}

创建一个CallExecuteObservable,包含原始Retrofit#Call,即转换前的OkhttpCall,返回Observable是BodyObservable。

屏幕快照 .png

我们最终返回的Observable就是BodyObservable对象,在DataModel数据源,通过subscribeOn将被观察者放到子线程,网络请求,observeOn让观察者在主线程,回调。

public Observable getRxLogin() {
    return api.postRxLogin(xxxx登陆参数)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
}

最终postLogin方法返回BodyObservable,设定subscribe方法在子线程工作。

public final Disposable subscribe(Consumer onNext, Consumer onError) {
    return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
屏幕快照 .png

调用#subscribe方法,参数自定义Consumer,最后,调用Observable类的抽象方法subscribeActual,BodyObservable子类实现它。

@Override 
protected void subscribeActual(Observer observer) {
    upstream.subscribe(new BodyObserver(observer));
}

upstream是内部委托类,CallExecuteObservable。向他注册subscribe一个观察者BodyObserver,封装外部Observer。
同样,最后进入CallExecuteObservable的subscribeActual方法,这里是真正进行网络请求的地方。调用Retrofit#Call#execute方法,此时,已经在子线程中,使用execute方法。

屏幕快照 .png

通过Retrofit#OkhttpCall获取Response,通过观察者BodyObserver的onNext和onComplete方法,调用封装外部Observer的同样方法。最终,通知到Consumer,在主线程回调。
使用RxJava这一套异步框架本质其实和前面默认工厂的ExecutorCallbackCall目的是一样的,实现子线程请求,主线程回调。用户调用interface接口网络请求方法流程图。

屏幕快照 .png

五、总结

基于interface设计,动态代理模式生成interface对象,接口方法转换成一个Http请求实体。

每个接口方法有一个ServiceMethod类,注解解析,Response和Request转换。

支持Rx异步框架实现回调路由,根据接口方法返回的参数类型,决定使用的工厂类型,将Retrofit的Call适配成Rx的Observable。

数据解析工厂可配置,支持多种数据类型。

将数据解析和异步框架分离,可扩展,耦合度低。


任重而道远

你可能感兴趣的:(Retrofit 原理)