美文网首页IT@程序员猿媛Android开发程序员
Retrofit用了哪些设计模式?动态代理?

Retrofit用了哪些设计模式?动态代理?

作者: SillyMonkey | 来源:发表于2019-04-02 09:53 被阅读40次

    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;
      }
    
      @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<Object, Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public Call<Object> adapt(Call<Object> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    
      static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;
        final Call<T> delegate;
    
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
          this.callbackExecutor = callbackExecutor;
          this.delegate = delegate;
        }
    
        @Override public void enqueue(final Callback<T> callback) {
          checkNotNull(callback, "callback == null");
    
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  if (delegate.isCanceled()) {
                    // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                  } else {
                    callback.onResponse(ExecutorCallbackCall.this, response);
                  }
                }
              });
            }
    
            @Override public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);
                }
              });
            }
          });
        }
    
        @Override public boolean isExecuted() {
          return delegate.isExecuted();
        }
    
        @Override public Response<T> execute() throws IOException {
          return delegate.execute();
        }
    
        @Override public void cancel() {
          delegate.cancel();
        }
    
        @Override public boolean isCanceled() {
          return delegate.isCanceled();
        }
    
        @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
        @Override public Call<T> clone() {
          return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
        }
    
        @Override public Request request() {
          return delegate.request();
        }
      }
    

    可以看到构造方法并没有做什么,只是将回调处理类传入。里面的其他方法后面调用的时候再来看。所以到这里我们还是不知道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用了哪些设计模式?动态代理?

        本文链接:https://www.haomeiwen.com/subject/stlwbqtx.html