前语

从署理形式动身,逐渐探索 Retrofit 的奥妙

署理形式

署理形式是一种结构型规划形式, 让你能够供给对象的替代品或其占位符。 署理控制着关于原对象的访问, 并答应在将请求提交给对象前后进行一些处理。

静态署理

关于静态署理自身的完结就很简略了,这儿能够简略看一下完结。

public interface IFooDao {
    void doSomething();
}
public class IFooDaoImpl implements IFooDao {
    @Override
    public void doSomething() {
        System.out.println(this.getClass().getName() + " work");
    }
}
public class IFooDaoProxy implements IFooDao {
    private IFooDao mIFooDao;
    public IFooDaoProxy(IFooDao mIFooDao) {
        this.mIFooDao = mIFooDao;
    }
    @Override
    public void doSomething() {
        this.mIFooDao.doSomething();
    }
}

顺次创立了服务接口、服务完结、服务署理

public class Client {
    public static void main(String[] args) {
        IFooDao prox = new IFooDaoProxy(new IFooDaoImpl());
        prox.doSomething();
    }
}

静态署理自身的完结很简略,其间涉及到的类也会比较清晰。这儿需求留意的是,服务接口的完结纷歧定经过界说 接口类的办法完结(即纷歧定是 interface ),抽象类也是一种选择,比方 Android 中的 Activity 为了完结在不经过版别的兼容性,便是采用了 AppCompatDelegate 这个抽象类。Activity 自身并不担任完结 setContentView() 之类的功能。而是将其署理给 AppCompatDelegate 的完结类 AppCompatDelegateImpl

动态署理

能够看到,在静态署理中,署理类需求提早创立,而经过动态署理,就能够在运行期完结创立署理类的作用。

顺次界说接口和注解

public interface IFooDao {
    void doSomething();
    @FakeProxy("proxy is yyds")
    int add(@EasyProxy String a, @Nullable String b);
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface EasyProxy {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FakeProxy {
    String value() default "";
}

上面界说了接口和 EasyProxyFakeProxy 两个注解。

    private static void dynamicProxy(IFooDao realDao) {
        IFooDao proxy = (IFooDao) Proxy.newProxyInstance(
                realDao.getClass().getClassLoader(),
                realDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.printf("proxy=%s,method=%s,args=%sn",
                                proxy.getClass().getSimpleName(), method.getName(), Arrays.toString(args));
                        System.out.println(method.getGenericReturnType());
                        System.out.println(Arrays.toString(method.getAnnotations()));
                        System.out.println(Arrays.toString(method.getGenericParameterTypes()));
                        System.out.println(Arrays.deepToString(method.getParameterAnnotations()));
                        // any-operation-before invoke
                        Object object = method.invoke(realDao, args);
                        // any-operation-after invoke
                        System.out.println("========================");
                        return object;
                    }
                }
        );
        proxy.doSomething();
        proxy.add("1", "2");
    }
public class IFooDaoImpl implements IFooDao {
    @Override
    public void doSomething() {
        System.out.println(this.getClass().getName() + " work");
    }
    @Override
    public int add(@EasyProxy String a, @Nullable String b) {
        return Integer.parseInt(a) + Integer.parseInt(b);
    }
}
// main 
dynamicProxy(new IFooDaoImpl());

能够看到,利用 Java 体系供给的 Proxy 静态办法 newProxyInstance ,只需求供给 IFooDao 的一个详细完结,那么就能够回来一个署理类,经过这个署理类 proxy 就能够访问 IFooDao 中界说的接口了。

能够看一下输出

proxy=$Proxy0,method=doSomething,args=null
void
[]
[]
[]
com.dp.internal.proxy.IFooDaoImpl work
========================
proxy=$Proxy0,method=add,args=[1, 2]
int
[@com.dp.internal.proxy.FakeProxy(value=proxy is yyds)]
[class java.lang.String, class java.lang.String]
[[@com.dp.internal.proxy.EasyProxy()], []]
========================

能够看到在 InvocationHandlerinvoke 办法中,咱们经过 method 能够获取到关于当时 method 的一切信息,包括其参数、办法注解、参数注解等信息。这儿值得留意的是 invoke 办法是有回来值的。

Retrofit

关于动态署理,Android 中运用最有名的莫过于 Retrofit 结构的完结了。下面就来看看 Retrofit 是如何运用动态署理的。

以下剖析基于 com.squareup.retrofit2:retrofit:2.9.0

Retrofit 究竟做了什么?

interface ApiService {
    @GET("wxarticle/chapters/json")
    fun getAccountList(): Call<WeChatCountList>
    @GET("wxarticle/chapters/json")
    fun getAccountJson(): Call<ResponseBody>
    @GET("wxarticle/chapters/json")
    fun getWeChatAccountList(): Observable<WeChatCountList>
}
  fun go2() {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .build()
        val service = retrofit.create(ApiService::class.java)
        val call = service.getAccountJson()
    }

这儿需求留意的是,ApiService 中界说的前两个办法回来值都是 Call 类型的。getWeChatAccountList 回来的是 Observable 类型。但这关于 Retrofit 全体的完结来说是没有什么大的区别的,无非只是多了一个 CallAdapter ,需求把 Call 履行的结果用 Observeable 进行一次包装。运用 Retrofit 的实质还是为了建议网络请求,关于网络请求来说最重要的是经过 OkHttp 创立 Call 的完结。因而,从这个视角动身再去看 Retrofit 的完结就会发现他其实简略。

Retrofit 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) {
        // 在 Android 上,这个 Executor 便是主线程
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      // 除了在 build 过程中增加的自界说 CallAdapter,还要增加体系默许的 Adapter 。
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      // 内置的 Converter 主要是对回来的 Response 进行再次处理
      converterFactories.add(new BuiltInConverters()); 
      // build 阶段自界说增加的 Converter
      converterFactories.addAll(this.converterFactories);
      // 如果支撑 Java,会增加支撑 Optional 操作的 Converter 
      converterFactories.addAll(platform.defaultConverterFactories());
      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

Retrofit 最中心的两个接口便是 CallAdapterConverter

CallAdapter

/**
 * Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
 * created by {@linkplain Factory a factory} which is {@linkplain
 * Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit} instance.
 */
public interface CallAdapter<R, T> {
  /**
   * Returns the value type that this adapter uses when converting the HTTP response body to a Java
   * object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type is
   * used to prepare the {@code call} passed to {@code #adapt}.
   *
   * <p>Note: This is typically not the same type as the {@code returnType} provided to this call
   * adapter's factory.
   */
  Type responseType();
  /**
   * Returns an instance of {@code T} which delegates to {@code call}.
   *
   * <p>For example, given an instance for a hypothetical utility, {@code Async}, this instance
   * would return a new {@code Async<R>} which invoked {@code call} when run.
   *
   * <pre><code>
   * &#64;Override
   * public &lt;R&gt; Async&lt;R&gt; adapt(final Call&lt;R&gt; call) {
   *   return Async.create(new Callable&lt;Response&lt;R&gt;&gt;() {
   *     &#64;Override
   *     public Response&lt;R&gt; call() throws Exception {
   *       return call.execute();
   *     }
   *   });
   * }
   * </code></pre>
   */
  T adapt(Call<R> call);
  /**
   * Creates {@link CallAdapter} instances based on the return type of {@linkplain
   * Retrofit#create(Class) the service interface} methods.
   */
  abstract class Factory {
    /**
     * Returns a call adapter for interface methods that return {@code returnType}, or null if it
     * cannot be handled by this factory.
     */
    public abstract @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit);
    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    /**
     * Extract the raw class type from {@code type}. For example, the type representing {@code
     * List<? extends Runnable>} returns {@code List.class}.
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
Converter

/**
 * Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
 * Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
 * into the {@link Retrofit} instance.
 */
public interface Converter<F, T> {
  @Nullable
  T convert(F value) throws IOException;
  /** Creates {@link Converter} instances based on a type and target usage. */
  abstract class Factory {
    /**
     * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for
     * response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
     * declaration.
     */
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }
    /**
     * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
     */
    public @Nullable Converter<?, RequestBody> requestBodyConverter(
        Type type,
        Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations,
        Retrofit retrofit) {
      return null;
    }
    /**
     * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
     * {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
     * QueryMap @QueryMap} values.
     */
    public @Nullable Converter<?, String> stringConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }
    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    /**
     * Extract the raw class type from {@code type}. For example, the type representing {@code
     * List<? extends Runnable>} returns {@code List.class}.
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
  • CallAdapter 望文生义,便是把 OkHttp 的 Call 经过适配器转换成任意咱们在接口办法中声明的回来类型,比方 Observeable .如果没有增加 自界说的 CallAdapter ,Retrofit 默许回来的便是 Call 类型的 Call. 那么其间的 T 又是怎样决定的呢?这就要靠 Converter 了。OkHttp 默许回来的是 Call<ResponseBody>
  • Converter 便是对回来的 ResponseBody 进行类型转换,比方咱们十分熟悉的 addConverterFactory(GsonConverterFactory.create()) .这个转换器详细是用什么库完结 json 到 object 的转换,关于 Retrofit 来说并不重要。

关于 Retrofit 来说,上述两个转换器内部的完结彻底是通明的,Retrofit 真是按责任链形式,将数据一层层的传递给 callAdapterFactoriesconverterFactories 中剩下的转换器,直到全部消费完结。

那么这个过程详细是怎样展开的呢?下面就从 Retrofit 的创立展开剖析。

Retrofit create 究竟创立了啥?

  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.
                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)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

create 办法总结起来很简略,便是创立了传入的 service 这个类的一个动态署理。这儿便是有意思的当地了,咱们知道在 Java 中 interface 类型的类是无法创立实例的,比方 ApiService 这个接口,咱们能够经过创立匿名类的办法完结这个接口,但是那样需求在完结接口的当地完结其一切办法的及其细节,这显然不是咱们想要的。

而 Retrofit 经过动态署理,适当所以动态持有了接口完结的引用,而当咱们单独调用接口中的每一个办法时,便会触发其 invoke 办法,在这个办法中经过 method 参数能够获取到当时调用办法的一切信息,经过这些信息就能够完结办法的详细细节了。能够说 Retrofit 的规划十分巧妙,利用接口彻底解耦了界说和完结。

Retrofit 完结细节

  fun go2() {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .build()
        val service = retrofit.create(ApiService::class.java)
        println("service is $service")
        println("service is ${service.javaClass.name}")
        val call = service.getAccountJson()
    }

咱们经过 create 创立了 ApiService 的实例。那么 service 究竟是什么呢?咱们能够看一下

service is retrofit2.Retrofit$1@14d3bc22
service is com.sun.proxy.$Proxy0

能够看到这个实例的 Class 类型是 com.sun.proxy.$Proxy0 。这个类型其实便是 InvocationHandler 中 invoke 办法的第一个参数 Object 的类型。

再看调用链,当咱们调用 service.getAccountJson() 办法时

重识动态署理

能够看到经过动态署理会调用到 invoke 办法中,最终会调用 loadServiceMethod(method).invoke(args) 办法。

Retrofit 只要默许 CallAdapter 和 Converter 时的履行流程。

重识动态署理

能够说 Retrofit 的全体规划十分的巧妙。

参考文档