Retrofit源码分析

简介

Retrofit turns your HTTP API into a Java interface.
官网简介,言简意赅。它可以将你的HTTP API简化成一种Java接口的方式书写。

1、地址

retrofit github地址:https://github.com/square/retrofit
retrofit官网:https://square.github.io/retrofit/
gradle依赖:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'

2、简单使用

STEP 1:定义接口

public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}

STEP 2:创建Retrofit实体类,并发起请求

// 1、创建Retrofit实体类
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

// 2、创建接口实现类
GitHubService service = retrofit.create(GitHubService.class);

// 3、通过实现类得到Call实例
// https://api.github.com/users/octocat/repos
Call<List<Repo>> repos = service.listRepos("octocat");

// 4、Call发起同步/异步请求
/*同步请求
try {
    Response<List<Repo>> execute = repos.execute();
} catch (IOException e) {
    e.printStackTrace();
}
*/
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {

    }

    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
});

原理

1、动态代理

retrofit的基础就是动态代理,通过retrofit.create() 方法点进去,可以看到,create方法实际就是使用动态代理生成了GitHubService接口的实现类:

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 {
                // If the method is a method from Object then defer to normal invocation.
                // 判断方法是否是Object的,如果是则不处理。
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    // 加载方法,此处为了效率,添加了缓存serviceMethodCache
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

简化一下就是这样的API,

    /**
     * @param loader     classLoader
     * @param interfaces 被代理的class,数组
     * @param h          被代理类的方法会被InvocationHandler中的invoke(Object proxy, Method method, Object[] args)接收
     * @return 生成的代理类
     */
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

2、反射

由上面的代码可以知道,通过使用动态代理,我们可以通过InvocationHandler拿到接口定义的方法。那我们怎么拿到我们定义的API呢?又如何拿到定义的参数呢?答案就是反射。

通过调用Retrofit.create()->loadServiceMethod()->ServiceMethod.parseAnnotations()->HttpServiceMethod.parseAnnotations() 来对method的注解进行解析。

// 此处为了效率,添加了缓存
ServiceMethod<?> loadServiceMethod(Method method) {
    ......
    result = serviceMethodCache.get(method);
    ......
    result = ServiceMethod.parseAnnotations(this, method);
    serviceMethodCache.put(method, result);
    ......
}

// 此处有部分检查返回值类型代码
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    ......
    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);
}

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ......
    adapterType = method.getGenericReturnType();
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    ......
    Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
    ......
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  }

HttpServiceMethod.parseAnnotations() 会返回CallAdapted 对象,通过调用invoke() 方法,生成OkHttpCall 对象,即我们通过接口定义的返回值。

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

当通过OkHttpCall 发起请求时,会调用OkHttpCall.createRawCall() 方法,通过反射获取到的参数就是在这里被拼接成Okhttp.Request 的,生成Okhttp.Call 对象,便可以通过Okhttp 发起请求。

  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

调用图解

1、retrofit.create()流程

retrofit流程create.jpg

2、call.enqueue()流程

retrofit enqueue流程.jpg

其他

用到的部分反射方法

// 获取方法的特定注解
MyGet myGet = method.getAnnotation(MyGet.class);

// 获取参数的注解
Annotation[][] paramsAnnotations = method.getParameterAnnotations();

// 获取返回方法返回值类型(包含泛型)
Type returnType = method.getGenericReturnType();

// 获取泛型的类型
Type[] types = ((ParameterizedType) returnType).getActualTypeArguments();

// 获取返回方法返回值类型(不包含泛型)
Class returnClass = method.getReturnType();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值