Retrofit是如何创建的?为什么要用动态代理

Retrofit的出现让Android的网络请求变得异常简单,同时可以很好的配合后台的REST接口。非常值得我们去探究一下它的原理。

Retrofit的使用

通常我们是Retrofit是和Rxjava配合使用,这里我们不做用法上的过多研究,主要看原理,所以下面的代码都是Retrofit的自身API,没有用Rxjava。

下面是一个普通get请求

1.新建接口

新建接口API.java文件:

public interface API {
    @GET("请求地址,但是不包括服务器的地址")
    Call<Response> get(
                            @Query("param1") String param1,//第一个参数
                            @Query("param2") int param2);//第二个参数
}

在@GET注解里面加上除去服务器链接的请求地址,@Query注解里面是请求的参数名。

2.创建Retrofit服务和请求客户端

新建一个单例类,RetrofitService.java(名字随意),在里面定义一个静态的OkHttpClient

private RetrofitService() {//构造方法私有化
    }

public static RetrofitService getInstance() {//双重校验
        if (instance == null) {
            synchronized (RetrofitService.class) {
                if (instance == null) {
                    instance = new RetrofitService();
                }
            }
        }
        return instance;
    }

private static OkHttpClient mOkHttpClient;

private static void initOkHttpClient() {
    HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();//日志拦截器
    mOkHttpClient = new OkHttpClient.Builder().cache(cache)
                            .addInterceptor(logInterceptor)//日志拦截器,按照需要添加
                            .connectTimeout(10, TimeUnit.SECONDS).build();//连接超时时间
}

向外提供一个方法,用于获取刚才的API接口

private volatile static API aPI = null;
    public static API createAPI() {
        if (aPI == null) {
            synchronized (RetrofitService.class) {
                if (aPI == null) {
                    initOkHttpClient();
                    aPI = new Retrofit.Builder()
                            .client(mOkHttpClient)
                            .baseUrl("服务器地址")
                            .addConverterFactory(GsonConverterFactory.create())//指定json处理库
                            .build().create(API.class);//将第一步创建的API接口传入
                }
            }
        }
        return aPI;
    }

3.开始发送请求

Call<Response> = call = RetrofitService.getInstance()
                .createShowAPI()
                .get("参数1", "参数2");

call.enqueue(new Callback<Response>() {
            @Override
            public void onResponse(Call<Response> call, Response<Response> response) {
                //请求成功的处理
            }

            @Override
            public void onFailure(Call<ShowApiResponse<ShowApiNews>> call, Throwable t) {
                //请求失败的处理
            }
        });

Retrofit的核心-动态代理

Retrofit是如何将我们定义的接口方法最后转化成请求发送出去呢,这里就到源码去看看

创建者模式

首先来看Retrofit的创建,这里使用了创建者模式

new Retrofit.Builder()
    .client(mOkHttpClient)
    .baseUrl("服务器地址")
    .addConverterFactory(GsonConverterFactory.create())//指定json处理库
    .build().create(API.class);//将第一步创建的API接口传入

首先来看Retrofit.Builder()这个类的构造方法

public static final class Builder {
    public Builder() {
      this(Platform.get());
    }
}

这里调用了一个带参数的构造方法,先看看Platform.get()是什么

  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

Platform.findPlatform

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

可以看到,这个Platform类,顾名思义其实就是平台。在Retrofit中,内置了两种平台,一种是Android,一种是Java8。不同的平台,处理的方式不同。继续往下看代码就明白了

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

这里先不深入探究,后面还会再回来,不过我们已经可以看到,Executor类在Android平台里是返回了MainThreadExecutor,里面提供了一个handler,并且这个handler是传入的主线程的Looper,也就是说在execute方法里面,handler.post实际上是在主线程(UI线程)执行的。

这里再回到Retrofit.Builder(),看看那个带参数的构造方法:

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

    Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;
      converterFactories.addAll(retrofit.converterFactories);
      adapterFactories.addAll(retrofit.adapterFactories);
      // Remove the default, platform-aware call adapter added by build().
      adapterFactories.remove(adapterFactories.size() - 1);
      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
    }

在这个构造方法里,对各种属性进行了初始化,来看看这些属性的定义

    private final Platform platform;//刚才看到的平台,这里是Android
    private @Nullable okhttp3.Call.Factory callFactory;//后面在分析
    private HttpUrl baseUrl;//服务器地址
    private final List<Converter.Factory> converterFactories = new ArrayList<>();//json解析工厂列表
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//后面再分析
    private @Nullable Executor callbackExecutor;//这里是Android的Executor,在主线程执行回调
    private boolean validateEagerly;//是否提前创建的标志

挨个看看这几个属性,这里有些属性的作用我们后面才知道,不过大部分看命名已经可以看到一些蹊跷:主要是callFactory和adapterFactories我们现在暂时不知道作用,继续往下看,在构造方法初始化之后,是调用Builder.build()方法

Builder.build()

    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);
    }
  }

在这里是将Builder的属性,再传给Retrofit的构造方法,来看看我们刚才疑惑的那两个属性怎么赋值:

callFactory

okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

callFactory在默认的情况下,其实是一个OkHttpClient,也就是说Retrofit的内部请求原理其实是用的OkHttp。还记得我们最开始创建的时候也传入了一个静态类OkHttpClient么,这之间有什么关系呢?

new Retrofit.Builder().client(mOkHttpClient)

Retrofit.Builder().client

    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

其实client里面传入的OkHttpClient也是赋值给了callFactory,所以callFactory就是OkHttp的网络请求客户端

adapterFactories

// 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));

创建了一个新的列表,并且加入了默认的CallAdapterFactory,刚才我们知道platform是Android,所以再看看之前的代码:

Platform.Android

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

defaultCallAdapterFactory返回的是ExecutorCallAdapterFactory

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
}

可以看到构造方法并没有做什么,只是将回调处理类传入。里面的其他方法后面调用的时候再来看。所以到这里我们还是不知道adapterFactories是干嘛的,但是我们看到了这个类里面有enqueue方法,还有一些处理响应的一些方法,所以我们可以知道它的作用是处理请求和响应,具体的用法后面继续看源码可以看到。

Retrofit.creat

在创建者初始化了所有属性之后,来到了Retrofit.creat方法

aPI = new Retrofit.Builder()
    .client(mOkHttpClient)
    .baseUrl("服务器地址")
    .addConverterFactory(GsonConverterFactory.create())//指定json处理库
    .build().create(API.class);

Retrofit.creat

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);//验证是否传入的为接口类
    if (validateEagerly) {//提前创建,默认为false,这里跳过
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // 方法定义所在的类,这里我们是定义在接口里面,返回false
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //platform.isDefaultMethod没做任何处理,直接返回false
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

这里看到了Retrofit的核心,使用动态代理来处理我们在接口中定义的方法。在调用我们定义的接口方法时,会来到动态代理类的invoke方法,然后执行最后的三行,在这里会解析定义的接口方法,并且做相应的处理。

总结

Retrofit在创建的过程中,有这么一些东西需要我们注意

platform

这个是Retrofit支持的平台,里面有Android和Java8,这里自然是Android

callFactory

执行请求的客户端,这里是OkHttpClient,在创建的时候.client传入

converterFactories

json解析处理工厂数组,这里是GsonConverterFactory。进行请求和响应的解析,将json字符串转换为具体的实体类

callAdapterFactories

请求和响应的具体处理适配器工厂数组,这里没有传的话默认为ExecutorCallAdapterFactory,如果需要使用rxjava,为RxJava2CallAdapterFactory

callbackExecutor

回调处理类,用于对回调数据的处理,这里是Android平台默认的MainThreadExecutor,使用Handler在主线程中处理回调。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容