安卓开源库源码学习

Retrofit 笔记

2019-01-27  本文已影响68人  英勇青铜5

一开始的目的是为了学习动态代理的使用,后来干脆把整个流程梳理了下

这不是完整的Retrofit,是纯Java环境下不涉及Android,Http的流程代码,Retrofit的精简代码,把内部一些设计和逻辑做了精简,主要是为了学习整个代码的大体设计和流程

Retrofit内关于OkHttp、Rx、Android相关的部分都去除了,其中okhttp3.call由一个RawCall来代替,内部没有做相关网络请求,只是做了下字符串拼接后println(),尽量还保持着Retrofit原有的类,有些地方,把注释也给粘贴过来了

Demo完整代码——>GitHub RetrofitDemo


1. Demo

使用也基本Retrofit的形式,Demo本身并无任何意义

1.1 Service

/** 获取币种Coin Service 接口 */
public interface IBtcService {
    /** 获取 BTC 信息 */
    Call<String> getBtcCoinInfo(@Content String content);
}

@Content是自己定义的一个注解,表明方法内是Content,作用类比@Path等,支持多个不同类型的Content,例如

getBtcCoinInfo(@Content String content1, @Content int content2)

返回类型必须是Call<>


1.2 使用

public class RetrofitDemo {
    public static void main(String[] args) {
        btcInfo();
    }

    /** BTC 信息 */
    private static void btcInfo() {
        Retrofit retrofit = new Retrofit.Builder().build();
        IBtcService iBtcService = retrofit.create(IBtcService.class);
        Call<String> call = iBtcService.getBtcCoinInfo("BTC $3512.6 ");
        try {
            Response<String> response = call.execute();
            System.out.println(response.body());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果就是Content前拼接当前时间

2019-1-27 12:01:27
BTC $3512.6 

2. 流程

基于Retrofit2.5.0版本,整个流程的代码都在core文件夹下

整个流程涉及有4个重要部分Retrofit,CallAdapter,Converter,OkHttpCall

Retrofit作为门面,关键点之一是crete()方法,使用动态代理通过CallAdatperRetrofit.Call转换为一个Service

Converter转换器,Request BodyResponse Body都要用

OkHttpCall,在实际的Retrofit中,持有着一个OkHttp3.Call,最终所有的有关网络请求的操作,都会在这里执行。由于我这里将网络请求去掉做精简,只是调用了RawCall.execute()来模拟网络请求

注意:

还有一个重要的东西CallbackExecutor,给精简去掉了。在Android内,由于UI线程的原因,网络请求时OkHttp会通过线程池运行在单独线程中,但本Demo为了简化流程,就网络请求模拟时,没有新创建线程, 对整个流程学习影响不大

实际在Retrofit中,Android环境默认情况下,会用一个Handler进行线程间通信将Response回调到UI线程


2.1 build()构建

Retrofit构造方法并不是private的,但一般都是通过内部的Builder来构建

 @Nullable
 private Executor callbackExecutor;

 Builder(Platform platform) {
     this.platform = platform;
 }

 public Builder() {
     this(Platform.get());
 }

 public Retrofit build() {

     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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
     callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

     // Make a defensive copy of the converters.
     List<Converter.Factory> converterFactories = new ArrayList<>(
                    1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

     // Add the built-in converter factory first. This prevents overriding its behavior but also
     // ensures correct behavior when using converters that consume all types.
     converterFactories.add(new BuiltInConverters());
     converterFactories.addAll(this.converterFactories);
     converterFactories.addAll(platform.defaultConverterFactories());
     return new Retrofit(converterFactories, callAdapterFactories);
 }

Executor可以先不关注

CallAdapter作用就是将Call转换为Service,默认情况下使用DefaultCallAdapterFactory

Converter转换器,默认情况下,使用BuiltInConverters来构建内置的转换器

在调用build()后,Retrofit就有了关联的CallAdapterFactory、ConveterFactory,但此时具体要使用的CallAdpater、Converter还不知道


2.2 动态代理

Retrofit作为门面,关键点之一是crete()方法,使用动态代理通过CallAdatperRetrofit.Call转换为一个Service

/**
 * 利用 JDK 动态代理,create 出一个 T(Service)
 * <p>
 * 需要将 Call 通过 CallAdapter 转换成 T
 * <p>
 * Single-interface proxy creation guarded by parameter safety
 *
 * @param service 代理接口 Class
 * @param <T>     代理
 * @return T, 代理 Service
 */
@SuppressWarnings("unchecked")
public <T> T create(final Class<T> service) {
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
            new InvocationHandler() {
                private final Object[] emptyArgs = new Object[0];
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
                }
            });
}

loadServiceMethod()从已创建的mServiceCache中获取当前方法对应的ServiceMethod,没有就创建一个新的put进去

private ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = mServiceCache.get(method);
    if (result != null) {
        return result;
    }
    synchronized (mServiceCache) {
        result = mServiceCache.get(method);
        if (result == null) {
            result = ServiceMethod.parseAnnotations(this, method);
            mServiceCache.put(method, result);
        }
    }
    return result;
}

2.2.1 ServiceMethod

ServiceMethod是一个抽象类,有一个HttpSeeviceMethod子类,负责将好的Request,CallAdapter,Converter组合起来

abstract class ServiceMethod<T> {
    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        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) {
            throw methodError(method, "Service methods cannot return void.");
        }

        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }

    abstract T invoke(Object[] args);
}

parseAnnotations()内,首先会通过RequestFactory.parseAnnotations()进行解析注解,然后构建出一个RequestFactory

再判断returnType返回类型,若为void,就会抛出异常,也就是创建的Service接口返回值不能为void

返回值为子类HttpServiceMethodparseAnnotations()方法返回值


HttpServiceMethod

内部主要有两个方法:

 /** 构建具体的 CallAdapter,Response Converter */
 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
         Retrofit retrofit, Method method, RequestFactory requestFactory) {
     // 创建 CallAdapter
     CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
     Type responseType = callAdapter.responseType();
     // Response Converter
     Converter<ResponseBody, ResponseT> responseConverter =
             createResponseConverter(retrofit, method, responseType);
     return new HttpServiceMethod<>(requestFactory, callAdapter, responseConverter);
 }
 
 /** ServiceMehod 抽象方法,将OkHttpCall进行适配*/
 @Override
 ReturnT invoke(Object[] args) {
     return mCallAdapter.adapt(new OkHttpCall<>(mRequestFactory, args, mResponseConverter));
 }

到了此时,具体要使用的CallApdater、Converter都已经创建好,就等着调用Service内的方法进行网络请求

mCallAdapter.adapt(),就是适配器模式,将Service适配成Call


2.3 Converter 转换器

Converter<F,T>是一个接口,将一个F -> T

两个地方要用,Request Body以及Response Body

Request Body需要解析注解,拿到注解的信息拼装用于网络请求的Request

Response Body就是将Json转换成为Bean,但Demo里这里简化了,只是直接将字符串进行返回


2.3.1 解析 Request Body 注解

ServiceMethod.parseAnnotations()内,RequestFactory.parseAnnotations()时会进行解析注解,组装Request

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
}

进行 build 构建RequestFactory

RequestFactory build() {
    // 创建的 Service 接口方法中的参数注解
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
    }
    return new RequestFactory(this);
}

parseParameter()就是根据Service接口内方法参数,使用parseParameterAnnotation()进行遍历对每个注解进行解析

/** 解析具体的参数注解 */
@Nullable
private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
    if (annotation instanceof Content) {
        validateResolvableType(p, type);

        Converter<?, String> converter =
                mRetrofit.stringConverter(type, annotations);
        return new ParameterHandler.Content<>(converter);
    }
    return null;
}

@Content是一个自己定义的注解

/** 内容注解 */
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Content {
}

ParameterHandler一个抽象类,根据注解,实现了一个Content子类,负责对注解进行解析拼接。注解是RUNTIME型的,为了加快读取,使用ParameterHandler

static final class Content<T> extends ParameterHandler<T> {

    private final Converter<T, String> mValueConverter;

    Content(Converter<T, String> valueConverter) {
        this.mValueConverter = valueConverter;
    }

    @Override
    void apply(StringBuilder builder, T value) throws IOException {
        builder.append(mValueConverter.convert(value));
    }
}

apply()将注解标记的参数拼接到StirngBuilder,在OkHttpCall内发起网路请求时,会通过这个StirngBuilder拿到Request Body


2.3.2 Response Body 转换

Retrofit.Builderbuild()方法内,添加了一个BuiltInConverters内置的转换器

converterFactories.add(new BuiltInConverters());

BuiltInConverters 内置转换器

/** 内置的转换器 */
final class BuiltInConverters extends Converter.Factory {
    @Nullable
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
        // 由于简化过程没有进行 http 请求,最终都转换成了 String
        if (type == String.class) {
            return ResponseBodyToStringConverter.INSTANCE;
        }

        // 返回 Void
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        return null;
    }

    /** Response Body 转换成 String */
    static final class ResponseBodyToStringConverter implements Converter<ResponseBody, String> {
        static final ResponseBodyToStringConverter INSTANCE = new ResponseBodyToStringConverter();

        @Override
        public String convert(ResponseBody value) throws IOException {
            return value.body();
        }
    }
}

ResponseBodyToStringConverter内直接返回了ResponseBody.body(),也就是Stirng本身


2.4 OkHttpCall

call.execute()时,最终会调用OkHttpCall内部逻辑,发起网络请求

@Override
public Response<T> execute() throws IOException {
    RawCall call;
    synchronized (this) {
        if (mExecuted) {
            throw new IllegalStateException("Already executed.");
        }
        mExecuted = true;
        call = mRawCall;
        if (call == null) {
            try {
                call = mRawCall = createRawCall();
            } catch (IOException | RuntimeException | Error e) {
                throw e;
            }
        }
    }
    return parseResponse(call.execute());
}

在方法内,会先创建RawCall

private RawCall createRawCall() throws IOException {
        return new RawCall(mRequestFactory.create(mArgs));
}

mRequestFactory.create()内,会将ParameterHandler存的解析的注解拼装的Request Body转成String

parseResponse()解析结果

private Response<T> parseResponse(String s) throws IOException {
    T body = mResponseConverter.convert(new ResponseBody(s));
    return Response.success(body);
}

根据创建的Response Body Converter来解析,之后构建一个Response类包装下,返回


3. 最后

整个精简后的Demo流程就这些,可以看看具体的代码

上一篇下一篇

猜你喜欢

热点阅读