说明:
本文的源码分析较为粗浅,和其他源码“解析”的文章相比并未特别详细,个人觉得看别人的源码,将整体的思路和大框架了解了,理解了其思想原理足矣
很重要的一点:
一定要带着质疑别人所谓的的“解析”去分析,一定要结合源码有自己的理解,不能完全相信他人的观点,即便是所谓的“大神”,人,总有犯错的时候。
如果文中有哪里不对的地方,请多指教。
从调用的流程开始分析
一、Retrofit的初始化
// 初始化配置Retrofit
retrofit = new Retrofit.Builder()
.baseUrl(AppConfig.BASE_URL)
//可设置自定义的client
.client(getOkHttpClient())
//可设置自定义的执行类CallAdapterFactory,可多个
.addCallAdapterFactory(new CustCallAdapterFactory())
//可设置自定义的解析类ConverterFactory,可多个
.addConverterFactory(new CustConvertFactory())
.build();
private OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(15 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(15 * 1000, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(xxxInterceptor)
.build();
}
return okHttpClient;
}
- 这里对Retrofit进行初始化,是通过构造者模式进行构建相关的参数数据
-
addConverterFactory
:为对象的序列化和反序列化添加转换器工厂 -
addCallAdapterFactory
:添加调用适配器工厂以支持除Call之外的服务方法返回类型
1、baseUrl:
-
baseUrl的方法有多个重载,最终通过构造HttpUrl传入,一直传递给
okhttp3.Request
中public Builder baseUrl(HttpUrl baseUrl) //最终的调用 public Builder baseUrl(String baseUrl)
Request build() { HttpUrl url; HttpUrl.Builder urlBuilder = this.urlBuilder; if (urlBuilder != null) { url = urlBuilder.build(); } else { // No query parameters triggered builder creation, just combine the relative URL and base URL. url = baseUrl.resolve(relativeUrl); if (url == null) { throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl); } } //省略好多... return requestBuilder .url(url) .method(method, body) .build(); }
-
如何动态切换Retrofit的BaseURL?
Retrofit中接收的baseUrl(String),最终是作为HttpUrl(okhttp3包里的)的类型参数传入的,在HttpUrl中有个host的字段,可以通过反射进行修改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); } public Builder baseUrl(HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); List
pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; }
二、Retrofit的请求和响应
// ① 获取接口实现
GitHubService service = retrofit.create(GitHubService.class);
// ② 调用(下面同步或异步请求选其一)
Call> repos = service.listRepos("octocat");
// ③ 同步请求
Response res = repos.execute();
// ③ 异步请求
repos.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call call, Throwable t) {
t.printStackTrace();
}
});
// 或者通过使用Observable,需要在初始化时进行配置:
// addCallAdapterFactory(RxJava3CallAdapterFactory.createSynchronous())
Observable call = mRetrofit.create(GitHubService.class).getUserData();
call.subsribe(Xxx)
1、接口的实现类:
从Retrofit
的示例来看,只需要一个接口及接口方法即可,调用者无需实现接口的具体实现类,就可以调用其内的方法,接口的实现类是从哪来的呢?
通过Retrofit#create
方法获得了接口的实现类,其内部是通过 动态代理(模式) Proxy.newProxyInstance
来实现的:
public T create(final Class 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) //对default方法进行判断
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
-
动态代理
Proxy.newProxyInstance
的参数和返回结果:-
classLoader
[参数]:类加载器会产生新类(实现的是传入的接口) -
class[]
[参数]:新类实现的接口,传进来(放到数组中) -
invocationHandler 接口
[参数]:执行方法体 -
T
[返回值]:一个封装了请求参数的接口的类,来发起网络请求
通过字节码(或打印其getClass())可得出类似于:class com.sun.proxy.$Proxy0
-
-
获取(动态代理)接口的实例对象
在Proxy
中,通过newProxyInstance
获取对象时,其中维护了一个代理类的缓存集合proxyClassCache
【是WeakCache
,其内部通过ConcurrentMap
进行实际的缓存】,从此缓存中获取生成的接口实现类。
而实现类的创建,是通过其固定的名称组装的类名://Proxy中: //固定规则 if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; //com.sun.proxy } String proxyName = proxyPkg + proxyClassNamePrefix + num; byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); try { //这里返回结果,加载byte[]来获取对象 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); }
-
InvocationHandler#invoke
内部解析:
1】Retrofit#loadServiceMethod
:
在每次调用请求接口方法的时候,每次都会通过调用invocationHandler
中的loadServiceMethod
方法,
在loadServiceMethod
方法内部,会解析得到具体的接口方法的实现(如例子中的listRepos
),进行调用invoke(args)
执行方法,发起网络请求。
2】platform.isDefaultMethod(method)
invocationHandler
中对default
方法进行了判断。如果是默认方法则对默认方法进行调用
default
是Java8的特性,在接口中可定义一些默认的方法:interface GithubApi { //默认方法 default void hello() { //do something... } }
注:其中
loadServiceMethod
返回的类型是ServiceMethod
,其具体实现类为HttpServiceMethod
。(似乎在之前的版本,2.2.0吧,ServiceMethod
是final
的,没有实现类。)
2、解析并装配参数(Okhttp请求)
在发送请求的时候,需要传入一些参数,对于Retrofit
,其请求的参数是放到注解上的,那它是如何对其进行解析的呢?是通过loadServiceMethod
方法内部对接口方法的注解及参数的解析而得。
-
Retrofit#loadServiceMethod
在loadServiceMethod
方法中,通过传入的Method
类型的参数来封装成ServiceMethod
对象。
获取具体的ServiceMethod对象流程(复用):
1】先从serviceMethodCache
缓存集合(ConcurrentHashMap
)中根据Method
取出ServiceMethod
对象,有则直接返回
2】若无,加锁,通过ServiceMethod#parseAnnotations
解析方法的注解信息,创建对应的接口方法的实现;
并缓存到集合中
ConcurrentHashMap
是个线程安全的集合(数组 + 链表 + 红黑树),因为网络请求都是在线程中去做的ServiceMethod
对象(具体实现为HttpServiceMethod
)中封装了各种解析工厂类等请求和响应的数据类信息(CallAdapter
和Converter
等等)。
ServiceMethod#parseAnnotations
1】通过RequestFactory
获取接口方法(如listRepos
方法)上的注解和参数等信息
如:baseUrl
、headers
等等
2】获取返回值的泛型参数类型:
method.getGenericReturnType()
3】最后返回具体的注解信息结果:
HttpServiceMethod.parseAnnotations
通过HttpServiceMethod
(ServiceMethod
的实现类)进行返回值包装类
和返回值
类的处理。HttpServiceMethod#parseAnnotations
1】通过HttpServiceMethod#createCallAdapter
得到CallAdapter
对象,方法内部根据参数进行匹配而得
2】通过createResponseConverter
得到Converter
对象,方法内部根据参数匹配而得
3】通过CallAdapter
和Converter
等对象构造出HttpServiceMethod
具体实现的子类对象并返回
① 若不是kotlin协程的方法,则返回CallAdapted
对象
② 否则返回协程方法相关的对象实例:SuspendForResponse
或SuspendForBody
ServiceMethod#invoke(args)
执行接口方法的调用,进而发起网络请求
invoke
是ServiceMethod
的抽象方法,由其直接子类HttpServiceMethod
实现HttpServiceMethod.invoke(args)
1】实现了父类ServiceMethod
的方法
2】创建Call对象
:
Call
call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
3】在实现的invoke
方法中,又转交给HttpServiceMethod.adapt
的抽象方法去完成的HttpServiceMethod.adapt
:
适配数据类型,并执行网络请求。
1】具体如何将Call
转换为指定的返回值包装类
的,最终是交给实现了HttpServiceMethod
的子类去完成的。
2】如在CallAdapted
中,其adapt
方法是直接交由传入的CallAdapter
的实现类来处理的
在使用的例子中是RxJava3CallAdapterFactory
内的具体实现RxJava3CallAdapter
3、“处理器”工厂:
这里我将类型适配器CallAdapter和解析转换器Converter称之为处理器,两者都用了 抽象工厂模式。
CallAdapter
:是对响应的数据进行转换,由T类型转换为R类型,这里用了 适配器模式
Converter
:是对请求数据和响应结果进行处理的数据类型转换的处理类。
-
CallAdapter
1】Retrofit
中定义了接口CallAdapter
,并由具体的子类实现如下方法:
①Type responseType();
:返回具体的内部类型,如UserBean
②T adapt(Call
:用于将call); retrofit2.Call
转换为 返回值包装类,如Observable
,并执行请求
2】Retrofit
默认只支持retrofit2.Call
作为接口方法的 返回值包装类,
可通过实现CallAdapter
接口进行扩展Call
,适配器的添加是通过在初始化Retrofit
时配置的:
Retrofit.Builder.addCallAdapterFactory
方法,可加多个适配器来转换 返回值包装类,
如可设置RxJava2CallAdapterFactory的Adapter
3】而真正使用的只有一个,在Retrofit#nextCallAdapter
中处理了相关逻辑
根据类型和注解的相关信息,循环List
进行匹配,
根据returnType
(Type
)、annotations
(Annotation[]
)等信息,匹配到了适配器(即返回结果不为null),则终止循环,直接返回这个factory。public interface CallAdapter
{ Type responseType(); T adapt(Call call); } -
Converter
1】Retrofit
中定义了接口Converter
,并由具体的子类实现convert
方法:
①T convert(F value)
:即从F
到T
(数据Bean)之间的转换操作。(多是处理POST
请求)
F
一般是RequestBody
(请求体)或是ResponseBody
(响应体),而T
是通过convert
方法返回的转换类型(如UserBean
)。
2】Retrofit
提供了addConverterFactory
方法,来配置添加转换实体的工厂对象,可加多个
① 在请求的时候,通过Retrofit#requestBodyConverter
方法(在构建RequestFactory
中调用的)获取指定的 请求 数据解析器。
② 通过Retrofit#responseBodyConverter
方法(在HttpServiceMethod#createResponseConverter
中获得的)获取指定的 响应 数据解析器。
3】在HttpServiceMethod#parseAnnotations
方法中调用了HttpServiceMethod#createResponseConverter
,
并在其内部获取到匹配的转换器,实际调用了Retrofit#responseBodyConverter
方法
4】在获取响应结果的转换器Retrofit#responseBodyConverter
(实际调用了nextResponseBodyConverter
方法)中,会循环遍历converterFactories
转换器集合(addConverterFactory
方法添加)
直到根据type
(Type
)、annotations
(Annotation[]
)等信息,匹配到转换器(即返回结果不为null),则终止循环,直接返回这个factory。public interface Converter
{ T convert(F value) throws IOException; }
4、请求的发起OkHttpCall
Retrofit
中真正发起网络请求的,最终还是通过的OkHttp
,所以要创建OkHttpCall
-
OkHttpCall
对象的创建:
在HttpServiceMethod.invoke(args)
的方法中,创建了OkHttpCall
对象
并将其实例传给了抽象方法adapt
,是由子类决定如何通过OkHttp
的实例发起网络请求@Override final @Nullable ReturnT invoke(Object[] args) { Call
call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } -
OkHttpCall#getRawCall -> createRawCall
在方法中,创建了真正的请求调用对象,并传入了请求的相关信息
返回的Call
实例,是OkHttp
中的请求对象,所以具体的请求还是由OkHttp
完成的。private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
OkHttpCall#enqueue / execute
方法:
1】OkHttpCall
类中是具体发起请求的地方,即重写的enqueue / execute
方法
2】在接口(GitHubService)中定义的方法(listRepos
)的返回类型Call
,这里的Call
实际上就是OkHttpCall
类型
3】当调用call.enqueue(Callback)
时,enqueue
就是OkHttpCall
中的具体实现,而Callback
(retrofit2.Callback)会在okhttp3.Callback
回调时进行转换。
4】HttpServiceMethod
的子类实现的adapt
方法中,根据传入的Call
,又调用了其enqueue
来执行请求的异步任务。
5、结果返回类型
例子中的Call
是如何返回的呢?>
-
类型说明
首先先明确一下,Retrofit中如何对这个返回类型中的各个部分定义的:- returnType:接口方法中的 返回值类型,如
Call
- >
- rawType:接口方法中的 返回值包装类,如
Call
- responseType:接口方法中返回的数据Bean类型,如
List
- returnType:接口方法中的 返回值类型,如
-
创建对象后的类型返回
1】ReturnT invoke
:
上面1中说到,请求的方法通过invoke
方法来调用的,那返回类型就从这里入手,
而invoke
是在ServiceMethod
中定义的,具体实现在HttpServiceMethod
的invoke
中(之前ServiceMethod
无实现类的时候,代码直接写在Retrofit
中来实现的),
而HttpServiceMethod#invoke
中又包了一层了adapt
抽象方法,adapt
定义的返回值的类型ReturnT
就是接口方法的返回类型(如Call
)- >
@Override final @Nullable ReturnT invoke(Object[] args) { Call
call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } protected abstract @Nullable ReturnT adapt(Call call, Object[] args); 2】
ReturnT adapt(Call
call, Object[] args)
adapt
方法的具体实现类是CallAdapted
(非kotlin协程),就在HttpServiceMethod
中,是个内部类。此方法是通过CallAdapter
来实现的,它其中的adapt
方法就是一个类型转换器,具体后面介绍。@Override protected ReturnT adapt(Call
call, Object[] args) { return callAdapter.adapt(call); } 3】
CallAdapter
的具体实现有很多,其中有个最原始的支持:DefaultCallAdapterFactory
,
此类中直接创建的匿名内部类CallAdapter
的实现没有具体转换,只转成了最基本的Call
类型,是因为要将线程中的请求结果,发送到主线程中,这其中就将Handler的消息发送包装了起来:return new CallAdapter
-
泛型类型的处理
在DefaultCallAdapterFactory
中,对相关的泛型参数类型进行了处理:@Override public @Nullable CallAdapter, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } if (!(returnType instanceof ParameterizedType)) { throw new IllegalArgumentException( "Call return type must be parameterized as Call
or Call extends Foo>"); } final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType); 1】先判断
rawType
为Call
,在DefaultCallAdapterFactory
的只对Call
类型处理
2】然后判断其中是否有泛型参数(即returnType
[如Call
] 是否是参数化类型- >
ParameterizedType
)
3】再从参数化类型中取出泛型实参(responseType
[如List
]),这里取的上限(Call extends Foo>
)的第一个(有可能有多个泛型实参)。 如何处理非原始支持的类型,如kotlin的
Deffered
:
同样的,也是需要实现CallAdapter
来具体的进行转换返回相应的类型。
6、如何获取返回结果的泛型实参
问题:java泛型有类型擦除,那是如何在运行时获得XxxBean(如List
)的呢?
上面说到,在获取returnType
之后,判断是否为泛型参数类型(ParameterizedType
),
然后再通过CallAdapter
中的getParameterUpperBound
(取类型的上限)
//Factory中
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
//Utils中
static Type getParameterUpperBound(int index, ParameterizedType type) {
//types即为 中的 Xxx, Yyy, ...这一数组
//获取泛型实参,主要在这里:getActualTypeArguments
Type[] types = type.getActualTypeArguments();
if (index < 0 || index >= types.length) {
throw new IllegalArgumentException(
"Index " + index + " not in range [0," + types.length + ") for " + type);
}
Type paramType = types[index];
//对通配符的判断
if (paramType instanceof WildcardType) {
return ((WildcardType) paramType).getUpperBounds()[0];
}
return paramType;
}
如果需要获取泛型类型,就要在混淆的时候,保留相关的方法处理,不能进行混淆。
若混淆了,生成的如下面的字节码上的注释都会被干掉,因此这些泛型类型都会被去掉,就无法获取到了。
- 原始代码:
public static Map
- , Set
- 编译后的字节码:
// access flags 0x9 // signature (Ljava/util/Map
;>;>;)Ljava/util/Map ;Ljava/util/Set ;>;>; // declaration: java.util.Map , java.util.Set >> test(java.util.Map >>) public static test(Ljava/util/Map;)Ljava/util/Map;
泛型擦除是一个无奈之举,因为在java1.5出现泛型之前的1.4版本及之前的版本,已经使用的很广泛了,为了兼容之前的代码程序。
C#是将泛型作为一个真实的类型存在,没有泛型擦除的问题。
7、Retrofit
中的kotlin协程
- 使用:可直接返回实体Bean,而不需要任何包装类
interface GitHubService {
@GET("getUserData")
suspend fun getUserData(): UserBean
}
data class UserBean(val userName: String, val userAge: Long)
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(GitHubService::class.java)
val job: Job = launch {
try {
val userBean: UserBean = service.getUserData()
println("userBean: $userBean")
} catch (e: Throwable) {
println("onFailure: $e")
}
}
-
内部解析
1】Retrofit
是以Java语言实现的,而suspend
挂起函数只能用于ktolin,不过都会编译为JVM
语言
通过将接口ApiService
反编译得到的Java类,结果如下:public interface ApiService { @GET("getUserData") @Nullable Object getUserData1(@NotNull Continuation var1); }
2】在
RequestFactory
中包含一个isKotlinSuspendFunction
的成员,用来标记当前解析的Method
是否为suspend
函数。
而isKotlinSuspendFunction
的值,是在RequestFactory#build
方法中跟进方法参数的最后一个是否为Continuation.class
来判定的。3】在处理方法的解析中,
HttpServiceMethod#parseAnnotations
内,根据isKotlinSuspendFunction
来处理kotlin协程的接口方法的解析结果
如果是,则返回SuspendForResponse
(得到Response
对象)或SuspendForBody
(得到数据Bean对象,如UserBean)对象,皆为HttpServiceMethod
的子类4】
SuspendForBody
实现的adapt
方法中,
将接口方法(getUserData)最后一个参数强转为Continuation
最终会调用KotlinExtensions.await
这个kotlin扩展方法5】
KotlinExtensions.await
方法中,
以suspendCancellableCoroutine
支持cancel的CoroutineScope
为作用域,依旧以Call.enqueue
发起OkHttp
请求,得到responseBody
后将其回调出去。
8、Retrofit在Android中的支持
支持主要在两方面:
① 是否支持Java8
,根据Android上是否启用Java 8
来判断,(Gradle中配置)
② 实现UI线程回调的Executor
,将回调结果切到UI线程
- 是否为Android平台的判断:
根据虚拟机的名称来判断,其中定义的Android
类,是Platform的唯一子类
private static Platform findPlatform() {
//根据 JVM 名字来判断使用方是否是 Android 平台
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android()
: new Platform(true);
}
- 是否支持
Java 8
:
通过Platform
中的hasJava8Types
成员来判断,在Platform#Android
类中,是通过构造方法传入的条件判断的:
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
-
UI线程的回调实现:
1】在Platform#Android
中,重写了defaultCallbackExecutor
方法,
返回了创建的MainThreadExecutor
对象,其中通过Handler
实现了将执行任务Runnable
转发到UI线程的逻辑static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } }
2】上面说到的
CallAdapter.Factory
,是用于处理接口返回值包装类(如Observable
)的适配器,在Retrofit#build
的时候,会将DefaultCallAdapterFactory
添加进去。而DefaultCallAdapterFactory
中就是处理对应的线程切换的操作。3】
DefaultCallAdapterFactory#get
方法返回的CallAdapter
对象,就是包装了ExecutorCallbackCall
(实现了Call
接口)对象,即具体实现了执行请求的ExecutorCallbackCall#enqueue
方法,在此方法中,进行了任务的执行:@Override public void enqueue(final Callback
callback) { Objects.requireNonNull(callback, "callback == null"); delegate.enqueue( new Callback () { @Override public void onResponse(Call call, final Response response) { callbackExecutor.execute( () -> { 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 call, final Throwable t) { callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t)); } }); }
9、如何支持RxJava
-
在构建
Retrofit
时,通过添加CallAdapterFactory
:retrofit = new Retrofit.Builder() .client(OKHttpFactory.INSTANCE.getOkHttpClient()) .baseUrl(AppConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) //看这里 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build();
RxJava2CallAdapterFactory
内部实现:
RxJava2CallAdapterFactory
中对返回值类型进行一系列操作,处理泛型参数等,并处理返回
其中的returnType
就是Observable
(XxxBean
就是自己定义的需要解析的类型),拿到returnType
之后,获取rawType
并进行一系列判断,判断各种RxJava
中定义的类型,最终将Obervable
的这种rawType
类型进行处理,然后在对泛型参数类型(即Observable
尖括号中的泛型类型)进行获取并处理,最终进行相关赋值,并返回CallAdapter>
-
还支持
Observable
>
请求的时候,具体实现为BodyObservable
的类型返回,真正实现adapt
的相关工作Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType); Class> rawObservableType = getRawType(observableType); if (rawObservableType == Response.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException( "Response must be parameterized" + " as Response
or Response extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); } else if (rawObservableType == Result.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException( "Result must be parameterized" + " as Result or Result extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); isResult = true; } else { responseType = observableType; isBody = true; } return new RxJava2CallAdapter( responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false); }
10、如何在反序列化时实例化对象
具体处理类是GsonConverterFactory
其中在处理request请求和response响应时,通过 gson.getAdapter
来返回TypeAdapter
,并传入 GsonRequestBodyConverter
或 GsonResponseBodyConverter
构造来处理解析的数据。在 TypeAdapterFactory
获取的TypeAdapter
实现的,一般是ReflectiveTypeAdapterFactory
,而ObjectTypeAdapter
中的read
方法是对基本数据类型进行处理解析。
具体的实例化是,在 Gson
构造函数中,创建了一个ConstructorConstructor
构造器的构造器,接收一个instanceCreators
(调用者传进来的):
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy, final Map> instanceCreators,
..., ...//省略好多入参....
) {
//省略好多....
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
//省略好多....
}
在ConstructorConstructor
中对对象的构造做了很多流程判断(如图),判断了是否有无参构造(通过newDefaultConstructor)
终极方案就是使用newUnsafeAllocator
中的native
方法来开辟对象内存空间:
public native Object allocateInstance(Class> var1) throws InstantiationException;
在终极方案中,进行实例化对象:
private ObjectConstructor newUnsafeAllocator(
final Type type, final Class super T> rawType) {
return new ObjectConstructor() {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
@SuppressWarnings("unchecked")
@Override public T construct() {
try {
//看这里
Object newInstance = unsafeAllocator.newInstance(rawType);
return (T) newInstance;
} catch (Exception e) {
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
+ "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
}
}
};
}
最终实例化了对象,实例化的时机,是在read
的时候:
//ReflectiveTypeAdapterFactory <-- 大多数都是这个factory
public static final class Adapter extends TypeAdapter {
private final ObjectConstructor constructor;
private final Map boundFields;
Adapter(ObjectConstructor constructor, Map boundFields) {
this.constructor = constructor;
this.boundFields = boundFields;
}
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
//看这里啊,这里啥都木有,就是实例化一个对象,字段全是默认值
T instance = constructor.construct();
//省略好多.....
return instance;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
//省略好多.....
}
}
设计模式举例:
1、Builder模式
2、工厂模式
- 抽象工厂模式:生产一系列的产品,关注的是一个大的集合
- 工厂方法模式:创建一类对象,一种产品
- 二者关联:抽象工厂通常是工厂方法来实现的
-
简单工厂:根据传递的参数(String、class等等)来创建对应的类对象(产品)
特点:接口较少,简单方便
缺点:增加产品的时候,需要增加/修改simpleFactory的代码
3、适配器模式
-
adapt
接收一种类型(接口),让实现者去转换为具体的结果,接收的是R
类型,返回的是T
类型。
除了Retrofit的CallAdapter
,还有Gson中的TypeAdapter
同样也是适配器模式
4、代理模式
访问子类(真正实现类)不可直接访问,要通过Proxy
的访问策略,来对内部私有的子类成员来进行控制访问。都实现了同样的接口(父类Subject)
需要注意的是,在Retrofit中创建实例的时候,虽然用了java中的动态代理,但并不是严格意义上的代理?难道不是代理了传入的接口service
么?
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
//省略好多...
}
- 代理模式 vs 装饰模式
- 代理模式:控制访问
- 装饰模式:增强功能
如何分析源码总结:
- 带着问题入手
- 从最熟悉的部分切入
- 看看有哪些可扩展性设计
- 分析下运用了哪些设计模式