Retrofit源码分析

通过一次网络请求,来分析Retrofit源码

Retrofit第三方开源库,最近在很多地方都看到有人在使用。用了之后,感觉这是一个很简洁,代码维护成本较低的开源库。

Retrofit一般会依赖OkHttp这个库,它访问网络依赖OkHttpClient,通常情况下都是:Retrofit + OkHttp一起使用的。

Retrofit也支持RxJava作为适配器工厂,Retrofit + OkHttp + RxJava 的组合也是很多开发者喜欢的。

在这里,通过Retrofit来请求一次网络,一步一步分析Retrofit内部原理与源码。



    compile "com.squareup.retrofit2:retrofit:2.0.2"
    compile "com.squareup.retrofit2:converter-gson:2.0.2"
    compile 'com.squareup.okhttp3:okhttp:3.2.0'

简单来说,Retrofit通过:注解 + 反射 + 动态代理。面向对象的形式来处理一次网络请求。

Retrofit让请求网络的代码变得简洁起来了,维护成本也低很多。

Retrofit让开发者只关心两个问题:

1,请求网络接口类的定义。

2,解析服务器传递过来的json生成Java Bean。


下面就从使用方式上来分析Retrofit的源码。

例如,让Retrofit来完成这样的一次网络请求,将服务器传递过来的json转化成Java Bean。

Get请求:


    https://api.douban.com/v2/fm/app_channels

1,首先,生成请求网络接口类。


    public interface AppChannelsApi {

        @GET("v2/fm/app_channels")
        Call<AppChannels> getAppCannels();
    }

2,分析服务器传递过来的json生成Java Bean。


    public class AppChannels {

        private List<GroupsBean> groups;

        ...

3,声明HostUrl。


    public class HostUrl {

        public static final String HOST = "https://api.douban.com/";
    }

4,创建OkHttpClient。


    public class HttpClient {

        private static OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();

        public static OkHttpClient get() {
            return mOkHttpClient;
        }
    }

5,生成Retrofit对象,通过Retrofit对象获取到接口的实现类。


    public class AppChannelsClient {

        private static AppChannelsApi api;

        public static AppChannelsApi get() {
            if (api == null) {
                synchronized (AppChannelsClient.class) {
                    if (null == api) {
                        Retrofit retrofit = new Retrofit.Builder()
                                .baseUrl(HostUrl.HOST)
                                .client(HttpClient.get())
                                .addConverterFactory(GsonConverterFactory.create())
                                .build();
                        api = retrofit.create(AppChannelsApi.class);
                    }
                }
            }
            return api;
        }
    }

6,使用Retrofit请求网络。


    Call<AppChannels> call = AppChannelsClient.get().getAppCannels();
    call.enqueue(new MyCallBack<AppChannels>() {
        @Override
        public void onSuccess(AppChannels data) {
            Log.i(TAG, "size:" + data.getGroups().size() + "  " + data.toString());
            mTextView.setText(data.toString());
        }

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

        }
    });

7,创建自己的CallBack,简化回调参数。


    public abstract class MyCallBack<T> implements Callback<T> {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            T data = response.body();
            if (data != null) {
                onSuccess(data);
            } else {
                onFailure(call, null);
            }
        }

        abstract public void onSuccess(T data);
    }

使用Retrofit请求网络就是这么简单,开发者只需要把注意力放在请求网络的接口类和服务器返回的Java Bean就行了。


现在开始分析源码:


    public interface AppChannelsApi {

        @GET("v2/fm/app_channels")
        Call<AppChannels> getAppCannels();
    }

可以看到使用了接口,以注解的方式设置网络请求方式,请求参数信息。

可以看得出,Retrofit想动态的获取到注解,请求参数信息,只能通过反射的方式拿到了。

下面分析Retrofit是怎么初始化,怎么拿到这些注解信息的:


    public class AppChannelsClient {

        private static AppChannelsApi api;

        public static AppChannelsApi get() {
            if (api == null) {
                synchronized (AppChannelsClient.class) {
                    if (null == api) {
                        Retrofit retrofit = new Retrofit.Builder()
                                .baseUrl(HostUrl.HOST)
                                .client(HttpClient.get())
                                .addConverterFactory(GsonConverterFactory.create())
                                .build();
                        api = retrofit.create(AppChannelsApi.class);
                    }
                }
            }
            return api;
        }
    }

进一步查看Retrofit源码:

静态内部类,Builder


    public static final class Builder {
    private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      // 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());
    }

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

可使用链式编程,快速初始化参数


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


    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

最终,以Retrofit构造器的形式生成Retrofit对象


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





    public final class Retrofit {
      private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

      private final okhttp3.Call.Factory callFactory;
      private final HttpUrl baseUrl;
      private final List<Converter.Factory> converterFactories;
      private final List<CallAdapter.Factory> adapterFactories;
      private final Executor callbackExecutor;
      private final boolean validateEagerly;

      Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
          List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
          Executor callbackExecutor, boolean validateEagerly) {
        this.callFactory = callFactory;
        this.baseUrl = baseUrl;
        this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
        this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
        this.callbackExecutor = callbackExecutor;
        this.validateEagerly = validateEagerly;
      }

可以看到,Retrofit获取对象的方式,是通过构造者模式。通过构造者这个静态内部类,链式编程的方式快速设置Retrofit参数,

最后将构造者设置的参数,以Retrofit构造器的形式生成Retrofit对象。

接下来,看Retrofit如何使用字节码,生成接口的实现类的。


    api = retrofit.create(AppChannelsApi.class);

进入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();

          @Override public Object invoke(Object proxy, Method method, 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);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
    }

可以看到,通过动态代理的方式,生成接口的实现了。

接下来看这行代码:


    ServiceMethod serviceMethod = loadServiceMethod(method);
    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.callAdapter.adapt(okHttpCall);

loadServiceMethod方法,将接口实现类的method字段传递进去,生成一个ServieMethod对象。进入到方法里:


    ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
    }



    public final class Retrofit {
      private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();


    final class ServiceMethod<T> {
      // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
      static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
      static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
      static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

      final okhttp3.Call.Factory callFactory;
      final CallAdapter<?> callAdapter;

      private final HttpUrl baseUrl;
      private final Converter<ResponseBody, T> responseConverter;
      private final String httpMethod;
      private final String relativeUrl;
      private final Headers headers;
      private final MediaType contentType;
      private final boolean hasBody;
      private final boolean isFormEncoded;
      private final boolean isMultipart;
      private final ParameterHandler<?>[] parameterHandlers;

可以看到,method对象作为Map集合的Key,存储了起来。ServiceMethod是一个Method的包装类。

可以猜的出,ServiceMethod是Retrofit的一次网络请求的具体Java Bean对象。

Retrofit的网络请求,以对象的方式存储到Map集合serviceMethodCache中。

接来下看这行代码:


    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

将一次网络请求的所有信息serviceMethod对象传递给了OkHttpCall,意思是这次网络请求准备交给OkHttp处理。


    final class OkHttpCall<T> implements Call<T> {
      private final ServiceMethod<T> serviceMethod;
      private final Object[] args;

      private volatile boolean canceled;

      // All guarded by this.
      private okhttp3.Call rawCall;
      private Throwable creationFailure; // Either a RuntimeException or IOException.
      private boolean executed;

      OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
      }

内部可以看到,OkHttpCall拥有一个网络请求serviceMethod


    return serviceMethod.callAdapter.adapt(okHttpCall);




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



    final class DefaultCallAdapterFactory extends CallAdapter.Factory {
      static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

      @Override
      public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }

        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }

          @Override public <R> Call<R> adapt(Call<R> call) {
            return call;
          }
        };
      }
    }

这行代码会将okHttpCall返回出去。也就是我们自定义接口,方法的返回值:


    @GET("v2/fm/app_channels")
    Call<AppChannels> getAppCannels();

我们请求网络的时候是这样的:


    Call<AppChannels> call = AppChannelsClient.get().getAppCannels();
    call.enqueue(new MyCallBack<AppChannels>() {
        @Override
        public void onSuccess(AppChannels data) {
            Log.i(TAG, "size:" + data.getGroups().size() + "  " + data.toString());
            mTextView.setText(data.toString());
        }

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

        }
    });

在OkHttpCall里也有enqueue方法:


    @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;

    ...

方法里找到:


     call = rawCall = createRawCall();


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



       call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
              throws IOException {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            callSuccess(response);
          }

          @Override public void onFailure(okhttp3.Call call, IOException e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }

可以看到,Retrofit里面的确是通过OkHttpClient进行网络请求的。


okhttp3.Call call = serviceMethod.callFactory.newCall(request);

这个callFactory就行Retrofit外面设置的OkHttpClient对象,只是以接口的方式显示,数据跟踪可以知道。

总的来说,当我们以调用接口实现类的方法:


Call<AppChannels> call = AppChannelsClient.get().getAppCannels();

Retrofit会通过动态代理,获取到接口对象,method字段,再通过反射获取到method字段中的注解,请求参数,

将信息存储到serviceMethod中,一个serviceMethod就包含了一次完整请求网络所需要的数据,

Host,Uri,请求参数,请求类型都有,再通过OkHttp的方式去请求网络,获取到json,

在通过Gson转化工厂将json转化成Java Bean,回调的方式传递出去

这就是Retrofit请求网络的源码分析。

注解 + 反射 + 动态代理 ,依赖OkHttp库。

Retrofit源码分析就到这里。

2016年7月06日 02:35:16

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值