android之Retrofit2原理解析

10 篇文章 0 订阅

1.前言

Retrofit2框架是对请求的封装,请求框架使用OKhttp框架,本篇不分析OKhttp框架,只分析Retrofit2框架如何将Java接口通过动态代理生成一个个的请求对象。

2.Retrofit2使用

//retrofit2包引用
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
/**
 * Retrofit工具测试类
 *
 * @author zhukui
 */
public abstract class RetrofitUtil {

    /**
     * 用户相关请求
     */
    public interface IUserRequest {
        @GET("userInfo/{userId}/")
        Call<ResponseBody> getUserInfo(@Path("userId") String userId);
    }

    /**
     * 测试方法
     */
    private void test() {
        //Retrofit对象创建,这里用的是建造者模式创建
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .build();

        //动态代理生成代理对象$Proxy0,并用接口多态
        IUserRequest service = retrofit.create(IUserRequest.class);

        //请求对象
        Call<ResponseBody> userInfo = service.getUserInfo("10086");

        //同步请求
        try {
            Response<ResponseBody> response = userInfo.execute();
            ResponseBody body = response.body();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //异步请求
        if(!userInfo.isExecuted()){
            userInfo.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    ResponseBody body = response.body();
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    t.printStackTrace();
                }
            });
        }
    }
    
}

3.Retrofit2源码分析

1.Retrofit对象创建

主要基于建造者模式创建,baseUrl()为主要方法。IUserRequest为用户类请求接口,getUserInfo为模拟获取用户信息接口,接口注解及接口参数配置可查看Retrofit官网说明,不是本篇侧重点,这里继续往下。

2.retrofit.create方法 - 重点

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

Utils.validateServiceInterface(service)判断是否是interface接口,如果这里是普通Java类型会直接抛出异常。

if (validateEagerly) { eagerlyValidateMethods(service);} 这里可以设置是否缓存解析对象。

Proxy.newProxyInstance这是调用java的动态代理生成了代理类。 

 public static Object newProxyInstance(ClassLoader loader,
                                       Class<?>[] interfaces,
                                       InvocationHandler h)

loader: 用哪个类加载器去加载代理对象

interfaces:动态代理类需要实现的接口

h:动态代理方法在执行时,会调用h里面的invoke方法去执行

 Proxy.newProxyInstance程序运行时会产生一个新类$proxy0

$proxy0类继承自Proxy类,实现了目标对象的父类接口

$proxy0类有多个Method成员变量,它的静态代码块给Method赋值为 接口的实现类 的对应的Method对象

$proxy0实现接口的方法调用了super.h.invoke(参数),这里的参数包括Method变量,返回值是接口返回值

//$proxy0的源码
public final class $Proxy0 extends Proxy implements IUserRequest {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
  
            m3 = Class.forName("接口的实现类的路径").getMethod("实现类的方法",  
                    new Class[0]);  
  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    } //static  
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final 返回类型的路径 接口实现类方法() {  
        try {  
            return (返回类型的路径)super.h.invoke(this, m3, null);  ;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
}  

//动态代理生成代理对象$Proxy0,并用接口多态
IUserRequest service = retrofit.create(IUserRequest.class);

//请求对象
Call<ResponseBody> userInfo = service.getUserInfo("10086");

接口.接口方法,实际是代理对象$proxy0 调用了对应的方法,$proxy0方法内部调用其父类的成员h的invoke方法,就是调用传入了InvocationHandler的invoke方法,至于返回值,那就看我们的InvocationHandler的invoke方法怎么写。Retrofit2重写了invoke方法返回值,实际为每个返回值为Call的方法返回了OkHttpCall对象,即service.getUserInfo("10086")获取到的返回是OkHttpCall。

3.loadServiceMethod分析

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

private final Map<Method, ServiceMethod<?>> 
                          serviceMethodCache = new ConcurrentHashMap<>();
 
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);
      }
    }
    return result;
  }

我们继续看ServiceMethod.parseAnnotations方法。

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 @Nullable T invoke(Object[] args);
}

ServiceMethod.parseAnnotations方法中RequestFactory.parseAnnotations()中进行方法注解、方法参数、方法参数注解等处理,并且负责创建请求时拼接resultful格式。

        @GET("userInfo/{userId}/")
        Call<List<String>> getUserInfo(@Path("userId") String userId);

userId传的是"10086",会将userId值赋值到userInfo/{userId}/中,即拼接为/userInfo/10086,

根据 baseUrl配置,最终 请求地址+请求参数 结果 :

baseUrl = https://api.github.com

relativeUrl = /userInfo/10086

最终请求为:https://api.github.com/userInfo/10086

RequestFactory中的一些方法如下: 

private final HttpUrl baseUrl;
private @Nullable String relativeUrl;

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


//这里处理方法,方法上的注解,参数类型,参数注解
Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }


RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        //解析方法注解
        parseMethodAnnotation(annotation);
      }
      //......
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) 
      {
        parameterHandlers[p] =
            //解析参数
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == 
            lastParameter);
      }
      //......
      return new RequestFactory(this);
 }

//解析参数
ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
         //.....
         //解析参数注解
         parseParameterAnnotation(p, parameterType, annotations, annotation);
         //.....
    }


//解析参数注解
@Nullable
private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
     //.....
        //处理参数注解Path
        Path path = (Path) annotation;
        String name = path.value();
        validatePathName(p, name);
     //.....
}


//创建请求
okhttp3.Request create(Object[] args) throws IOException {
 //.....
}


继续看ServiceMethod.parseAnnotations的返回值:

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

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

   /**
    * parseAnnotations方法
    */
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {

      //...

      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
}

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

static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    private final boolean isNullable;

     //...
}

可以看到 HttpServiceMethod是ServiceMethod子类,最终返回的SuspendForBody也是ServiceMethod子类,到这里就可以看到上面invoke方法的最终实现了。

4.invoke方法

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

我们可以看到此处new OkHttpCall()对象,并且传了解析了方法注解及参数注解的RequestFactory对象作为参数,这里就实现了为每一个返回值为Call的方法返回了实际请求对象。

4.总结

Retrofit2通过动态代理,获得接口方法的参数和相关注解,生成OkHttpCall,OkHttpCall中使用okhttp3.Call发起Http请求。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值