前语
从署理形式动身,逐渐探索 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 "";
}
上面界说了接口和 EasyProxy
、FakeProxy
两个注解。
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()], []]
========================
能够看到在 InvocationHandler
的 invoke
办法中,咱们经过 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 最中心的两个接口便是 CallAdapter
和 Converter
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>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> 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 真是按责任链形式,将数据一层层的传递给 callAdapterFactories
和 converterFactories
中剩下的转换器,直到全部消费完结。
那么这个过程详细是怎样展开的呢?下面就从 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 的全体规划十分的巧妙。