文章目录
概述
在 Android 开发中,通过网络请求获取服务端数据是一项基本且常见的需求。目前有多种网络请求框架可供选择,其中 Android-Async-Http、Volley、OkHttp 和 Retrofit 是较为流行的、开源的网络请求框架。如何选择它们?孰优孰劣?仁者见仁智者见智,我个人觉得适合的就是最好的,不要盲目跟风去更换掉之前选用的网络请求框架,毕竟老代码那是牵一发而动全身哈!对于新项目来说,选择一个好用的网络请求框架,还是很有必要的,而 Retrofit 作为当下最火的一个网络开源请求库,还是值得学习并尝试使用的。
一、Retrofit 简介
Retrofit 是一个在 Android 开发中常用的网络请求框架。是 Square 公司基于他们自己的另一个比较火的网络库 OkHttp,进行封装的一个 RESTful 的 HTTP 网络请求框架。其提供了简洁而强大的 API,用于与 RESTful 服务进行通信。
- App 应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作;
- 请求获取到服务端的响应后,OkHttp 将服务端返回的、原始的数据交给 Retrofit, Retrofit 再根据用户的需求对结果进行解析。
Retrofit 的一些主要特点和优势:
- 简单易用的 API:Retrofit 提供了简洁、直观的 API,使得定义和执行网络请求变得非常简单。通过定义接口,并使用注解来描述请求参数和响应数据,可以轻松地与 RESTful API 进行交互;
- 自动化网络请求处理:Retrofit 处理了大部分网络请求的细节,包括请求的构建、执行、响应的解析等,大大简化了网络请求的代码编写过程;
- 内置支持 RxJava:Retrofit 2.0 内置支持 RxJava,可以方便地将网络请求转换为 Observables 或 Singles,实现更加优雅的异步编程模式;
- 请求和响应的数据转换:Retrofit 支持多种数据格式的转换,包括:Gson、JSON、XML、Protobuf 等,可以方便地进行数据的序列化和反序列化;
- 灵活的请求配置:Retrofit 允许你配置全局的请求参数,包括:连接超时、读取超时、请求头、日志输出等,以满足不同场景下的需求;
- 强大的错误处理机制:Retrofit 提供了灵活的错误处理机制,可以根据不同的 HTTP 状态码和错误情况进行统一处理,使得应用程序在遇到错误时能够优雅地处理并给出相应的提示。
Retrofit 与其它主流网络请求库之间的功能与区别:
二、Retrofit 源码剖析
1. Retrofit 网络请求过程
结合上图,解释一下 Retrofit 网络请求过程:
- 通过解析网络请求接口的注解配置网络请求参数
- 通过动态代理生成网络请求对象
- 通过网络请求适配器将网络请求对象进行平台适配(包括:Android、RxJava、Guava 和 Java8)
- 通过网络请求执行器发送网络请求
- 通过数据转换器解析服务器返回的数据
- 通过回调执行器切换线程(子线程切到主线程)
- 用户在主线程处理并展示返回结果
本文不准备详细介绍 Retrofit 的使用,主要是深入源码剖析其原理,下面就根据上面的请求过程,逐步剖析 Retrofit 的源码调用过程,注意:后续的源码基于 Retrofit 2.5.0 版本进行分析。
2. Retrofit 实例构建
Retrofit 实例是使用建造者模式通过 Builder 类进行创建的:
OkHttpClient client =newOkHttpClient.Builder().addInterceptor(newTokenHeaderInterceptor())// 动态添加token.addInterceptor(newNullResponseInterceptor())// 返回空字符的时候显示.connectTimeout(CONNECTION_TIMEOUT,TimeUnit.SECONDS).writeTimeout(CONNECTION_TIMEOUT,TimeUnit.SECONDS).readTimeout(CONNECTION_TIMEOUT,TimeUnit.SECONDS).build();Retrofit retrofit =newRetrofit.Builder().baseUrl(mBaseUrl).client(client)// okhttp实例对象.addConverterFactory(GsonConverterFactory.create())// 添加转换器工厂.addCallAdapterFactory(RxJava2CallAdapterFactory.create())// 请求指定适配器 RxJava.build();
2.1 Retrofit.java
publicfinalclassRetrofit{// 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)// 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等privatefinalMap<Method,ServiceMethod<?>> serviceMethodCache =newConcurrentHashMap<>();// 网络请求执行器的工厂,其作用是生产网络请求执行器 Call,Retrofit 默认使用 OkHttpfinalokhttp3.Call.Factory callFactory;finalHttpUrl baseUrl;// 网络请求的 url 基地址// 存放数据转换器工厂的集合,数据转换器工厂是用来生产数据转换器(Converter)finalList<Converter.Factory> converterFactories;// 存放网络请求适配器工厂的集合,网络请求适配器工厂是用来生产网络请求适配器(CallAdapter)finalList<CallAdapter.Factory> callAdapterFactories;final@NullableExecutor callbackExecutor;// 回调方法执行器// 是否提前对业务接口中的注解进行验证转换的标志位finalboolean validateEagerly;Retrofit(okhttp3.Call.Factory callFactory,HttpUrl baseUrl,List<Converter.Factory> converterFactories,List<CallAdapter.Factory> callAdapterFactories,@NullableExecutor callbackExecutor,boolean validateEagerly){this.callFactory = callFactory;this.baseUrl = baseUrl;this.converterFactories = converterFactories;// Copy+unmodifiable at call site.this.callAdapterFactories = callAdapterFactories;// Copy+unmodifiable at call site.this.callbackExecutor = callbackExecutor;this.validateEagerly = validateEagerly;}}
通过 Retrofit 的构造函数构建一个 Retrofit 实例对象,并配置好类里面的各成员变量。
工厂模式:设计模式中工厂模式,是将”类实例化的操作”与“使用对象的操作”分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。
2.2 Retrofit.Builder()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{privatefinalPlatform platform;[email protected] callFactory;private@NullableHttpUrl baseUrl;privatefinalList<Converter.Factory> converterFactories =newArrayList<>();privatefinalList<CallAdapter.Factory> callAdapterFactories =newArrayList<>();private@NullableExecutor callbackExecutor;privateboolean validateEagerly;Builder(Platform platform){this.platform = platform;}publicBuilder(){// 继续调用自身有参的构造方法,并通过调用 Platform.get() 方法传入了 Platform 对象this(Platform.get());}}}
静态内部类 Builder 的成员变量与 Retrofit 类的成员变量是对应的,通过 Builder 类对 Retrofit 类的成员变量进行赋值。
建造者模式:将一个复杂对象的构建与表示分离,使得用户在不知道对象的创建细节情况下就可以直接创建复杂的对象。
2.2.1 Platform.get()
classPlatform{privatestaticfinalPlatformPLATFORM=findPlatform();staticPlatformget(){// PLATFORM 是一个静态的 final 类型的变量,通过 findPlatform() 方法来赋值returnPLATFORM;}privatestaticPlatformfindPlatform(){try{// 通过 Class.forName(),JVM 查找并加装指定的类(即 Java 会执行该类的静态代码段)Class.forName("android.os.Build");if(Build.VERSION.SDK_INT!=0){// 如果是 Android 平台,就创建并返回一个 Android 对象并返回returnnewAndroid();}}catch(ClassNotFoundException ignored){}try{// 支持 Java 8Class.forName("java.util.Optional");returnnewJava8();}catch(ClassNotFoundException ignored){}returnnewPlatform();}}
由 Platform.get() 方法可以看出,Retrofit 2.5 目前支持 Android 和 Java 平台,翻看之前 2.0 版本的代码,那会儿还支持 iOS 平台。在方法中通过判断返回对应平台的实例对象,这里返回的是 Android 的实例对象,即指定了运行平台为 Android。
2.2.2 Android 平台
classPlatform{staticclassAndroidextendsPlatform{@OverridepublicExecutordefaultCallbackExecutor(){// 新建并返回 MainThreadExecutor 实例作为默认的回调方法执行器returnnewMainThreadExecutor();}// Retrofit 中提供了四种 CallAdapterFactory:ExecutorCallAdapterFactory(默认)、// GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory@OverrideList<?extendsCallAdapter.Factory>defaultCallAdapterFactories(@NullableExecutor callbackExecutor){if(callbackExecutor ==null)thrownewAssertionError();// 创建默认的网络请求适配器工厂,生产的 adapter 使得 Call 在异步调用时在指定的 Executor 上执行回调ExecutorCallAdapterFactory executorFactory =newExecutorCallAdapterFactory(callbackExecutor);returnBuild.VERSION.SDK_INT>=24?asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory):singletonList(executorFactory);}@OverrideintdefaultCallAdapterFactoriesSize(){// 默认请求适配器工厂数量returnBuild.VERSION.SDK_INT>=24?2:1;// 大于7.0 2 个 其他 1 个}@OverrideList<?extendsConverter.Factory>defaultConverterFactories(){// 默认转换器工厂returnBuild.VERSION.SDK_INT>=24?singletonList(OptionalConverterFactory.INSTANCE):Collections.<Converter.Factory>emptyList();}@OverrideintdefaultConverterFactoriesSize(){// 默认转换器数量returnBuild.VERSION.SDK_INT>=24?1:0;// 大于7.0 1 个 其他 0 个}staticclassMainThreadExecutorimplementsExecutor{// 使用 Android 主线程的 Looper 来新建一个 HandlerprivatefinalHandler handler =newHandler(Looper.getMainLooper());@Overridepublicvoidexecute(Runnable r){// 通过上面新建的 Handler 发送消息,将消息发送到UI主线程,在UI线程对网络请求返回数据进行处理
handler.post(r);}}}}
至此,Retrofit 的 Builder 类介绍完毕,通过跟踪查看代码可知,在 Builder 类中设置了默认的平台类型对象:Android、网络请求适配器工厂:CallAdapterFactory(CallAdapter 用于对原始 Call 进行再次封装,如结合 RxJava 使用时将 Call 封装成 Observable)、数据转换器工厂:ConverterFactory 和回调执行器:CallbackExecutor。
注意:这里只是设置了默认值,但未真正配置到具体的 Retrofit 类的成员变量当中。
2.3 Retrofit.Builder().baseUrl()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{......private@NullableHttpUrl baseUrl;......// 配置 Retrofit 类的网络请求基地址 baseUrlpublicBuilderbaseUrl(String baseUrl){checkNotNull(baseUrl,"baseUrl == null");// 通过 HttpUrl.get() 方法把 String 类型的 url 参数转化为适合 OkHttp 的 HttpUrl 类型returnbaseUrl(HttpUrl.get(baseUrl));}publicBuilderbaseUrl(HttpUrl baseUrl){checkNotNull(baseUrl,"baseUrl == null");// 把 baseUrl 参数分割成几个路径碎片List<String> pathSegments = baseUrl.pathSegments();// 通过检测最后一个 Segment 来检查 baseUrl 参数是不是以"/"结尾,不是则抛出异常if(!"".equals(pathSegments.get(pathSegments.size()-1))){thrownewIllegalArgumentException("baseUrl must end in /: "+ baseUrl);}this.baseUrl = baseUrl;returnthis;}}}
通过 HttpUrl.get() 方法把 String 类型的 url 参数转化为适合 OkHttp 的 HttpUrl 类型,然后调用 baseUrl() 方法传入刚转化的 HttpUrl,并通过检测最后一个 Segment 来检查传入的参数是不是以 “/” 结尾,如果是则赋值保存传入的 HttpUrl,不是则抛出异常。
2.4 Retrofit.Builder.client()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{[email protected] callFactory;......// 用于请求的 HTTP 客户端,OkHttpClient 是 Call.Factory 接口的实现类publicBuilderclient(OkHttpClient client){returncallFactory(checkNotNull(client,"client == null"));}// 为创建 Call 实例指定一个自定义调用工厂,设置 client 时自动设置 Call.FactorypublicBuildercallFactory(okhttp3.Call.Factory factory){this.callFactory =checkNotNull(factory,"factory == null");returnthis;}}}
Retrofit.Builder.client() 方法为创建网络请求 Call 指定一个自定义调用工厂,这里注意:OkHttpClient 是 Call.Factory 接口的实现类。
2.5 Retrofit.Builder.addConverterFactory()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{......privatefinalList<Converter.Factory> converterFactories =newArrayList<>();......// 为对象的序列化和反序列化添加数据转换器工厂publicBuilderaddConverterFactory(Converter.Factory factory){
converterFactories.add(checkNotNull(factory,"factory == null"));returnthis;}}}
Builder.addConverterFactory() 方法为对象的序列化和反序列化添加数据转换器工厂 ConverterFactory,下面以 GsonConverterFactory 为例,调用 GsonConverterFactory.create() 方法来创建实例对象。
2.5.1 GsonConverterFactory.create()
publicfinalclassGsonConverterFactoryextendsConverter.Factory{// 使用默认的 Gson 实例创建一个 GsonConverterFactory 实例用于数据转换// 编码到 JSON 并从 JSON 解码(当头部没有指定字符集时)将使用UTF-8publicstaticGsonConverterFactorycreate(){// 继续调用重载的 create() 方法并传入一个新建的 Gson 实例returncreate(newGson());}// 重载的 create() 方法,作用与上面的类似@SuppressWarnings("ConstantConditions")// Guarding public API nullability.publicstaticGsonConverterFactorycreate(Gson gson){if(gson ==null)thrownewNullPointerException("gson == null");// 创建一个含有 Gson 实例对象的 GsonConverterFactoryreturnnewGsonConverterFactory(gson);}privatefinalGson gson;privateGsonConverterFactory(Gson gson){this.gson = gson;}@OverridepublicConverter<ResponseBody,?>responseBodyConverter(Type type,Annotation[] annotations,Retrofit retrofit){TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));returnnewGsonResponseBodyConverter<>(gson, adapter);}@OverridepublicConverter<?,RequestBody>requestBodyConverter(Type type,Annotation[] parameterAnnotations,Annotation[] methodAnnotations,Retrofit retrofit){TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));returnnewGsonRequestBodyConverter<>(gson, adapter);}}
GsonConverterFactory.creat() 方法中创建了一个含有 Gson 实例的 GsonConverterFactory 实例对象, 并返回给 Builder.addConverterFactory() 方法作为方法的入参将其放入到 converterFactories 集合中。
2.6 Retrofit.Builder.addCallAdapterFactory()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{......privatefinalList<CallAdapter.Factory> callAdapterFactories =newArrayList<>();......// 添加网络请求 Call 的适配器工厂,以支持除 Call 以外的服务方法返回类型publicBuilderaddCallAdapterFactory(CallAdapter.Factory factory){
callAdapterFactories.add(checkNotNull(factory,"factory == null"));returnthis;}}}
Builder.addCallAdapterFactory() 方法为网络请求 Call 添加适配器工厂,以支持除 Call 以外的服务方法返回类型。本文以 RxJava2CallAdapterFactory 为例,调用 RxJava2CallAdapterFactory.create() 方法来创建实例对象。
2.6.1 RxJava2CallAdapterFactory.create()
publicfinalclassRxJava2CallAdapterFactoryextendsCallAdapter.Factory{publicstaticRxJava2CallAdapterFactorycreate(){// 继续调用 RxJava2CallAdapterFactory 有参构造方法,只是 Scheduler 传入为 nullreturnnewRxJava2CallAdapterFactory(null);}privatefinalScheduler scheduler;privateRxJava2CallAdapterFactory(Scheduler scheduler){this.scheduler = scheduler;}@OverridepublicCallAdapter<?>get(Type returnType,Annotation[] annotations,Retrofit retrofit){Class<?> rawType =getRawType(returnType);// 获取当前方法参数的具体类型if(rawType ==Completable.class){// 返回类型是否是Completable类// Completable 没有参数化(这是该方法的其余部分所处理的),因此只能用单个配置创建它returnnewRxJava2CallAdapter(Void.class, scheduler,false,true,false,false,false,true);}// 由于本文是结合 RxJava 进行使用的,因此返回值类型是 Observable 类型的boolean isFlowable = rawType ==Flowable.class;// isFlowable 为 falseboolean isSingle = rawType ==Single.class;// isSingle 为 falseboolean isMaybe = rawType ==Maybe.class;// isMaybe 为 falseif(rawType !=Observable.class&&!isFlowable &&!isSingle &&!isMaybe){returnnull;// 不是 Completable、Flowable、Single、Maybe 和 Observable 则返回 null}boolean isResult =false;boolean isBody =false;Type responseType;if(!(returnType instanceofParameterizedType)){// 非参数化类型String name = isFlowable ?"Flowable": isSingle ?"Single":"Observable";thrownewIllegalStateException(name +" return type must be parameterized"+" as "+ name +"<Foo> or "+ name +"<? extends Foo>");}// 获取泛型参数的上界Type observableType =getParameterUpperBound(0,(ParameterizedType) returnType);Class<?> rawObservableType =getRawType(observableType);// 获取当前方法参数的具体类型if(rawObservableType ==Response.class){// 如果是 Responseif(!(observableType instanceofParameterizedType)){// 非参数化类型 抛出异常thrownewIllegalStateException("Response must be parameterized"+" as Response<Foo> or Response<? extends Foo>");}// 获取当前返回类型的具体类型
responseType =getParameterUpperBound(0,(ParameterizedType) observableType);}elseif(rawObservableType ==Result.class){// 如果是 Result if(!(observableType instanceofParameterizedType)){// 非参数化类型 抛出异常thrownewIllegalStateException("Result must be parameterized"+" as Result<Foo> or Result<? extends Foo>");}// 获取当前返回类型的具体类型
responseType =getParameterUpperBound(0,(ParameterizedType) observableType);
isResult =true;}else{// 如果都不符合,则默认情况下返回值类型为 observableType
responseType = observableType;
isBody =true;// isBody 置为 true}// 根据上面的值,实例化 RxJava2CallAdapter 对象returnnewRxJava2CallAdapter(responseType, scheduler, isResult, isBody, isFlowable,
isSingle, isMaybe,false);}}
RxJava2CallAdapterFactory.creat() 方法中创建 RxJava2CallAdapterFactory 实例对象, 并返回给 Builder.addCallAdapterFactory() 方法作为方法的入参将其放入到 callAdapterFactories 集合中。
2.7 Retrofit.Builder.build()
publicfinalclassRetrofit{publicstaticfinalclassBuilder{......private@NullableHttpUrl baseUrl;......Builder(Platform platform){this.platform = platform;}/**
* 使用配置的值创建 Retrofit 实例
* 注意:如果 client() 方法和 callFactory() 方法都没有被调用,那么默认的 OkHttpClient 将被创建和使用
*/publicRetrofitbuild(){if(baseUrl ==null){thrownewIllegalStateException("Base URL required.");}okhttp3.Call.Factory callFactory =this.callFactory;if(callFactory ==null){// 如果没有指定 callFactory,则创建并配置默认的网络请求执行器 OkHttpClient
callFactory =newOkHttpClient();}Executor callbackExecutor =this.callbackExecutor;if(callbackExecutor ==null){// 如果没有指定 callbackExecutor,则使用 platform 默认的回调执行器// Android 平台默认是 MainThreadExecutor
callbackExecutor = platform.defaultCallbackExecutor();}// 创建 CallAdapterFactory 的副本,并将 platform 默认的 CallAdapterFactories 添加到集合的末尾// 即 CallAdapterFactory 存储顺序:自定义 CallAdapterFactory 根据添加顺序优先执行,默认的 CallAdapterFactory 最后执行List<CallAdapter.Factory> callAdapterFactories =newArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));// 创建 ConverterFactory 的副本,其集合的长度 size 是 platform 默认的 defaultConverterFactoriesSize// 加上当前 this.converterFactories.size() 再加 1List<Converter.Factory> converterFactories =newArrayList<>(1+this.converterFactories.size()+ platform.defaultConverterFactoriesSize());// 首先添加内置的转换器工厂,其次是 GsonConverterFactory(添加到集合的第二位),最后是platform默认的 defaultConverterFactories
converterFactories.add(newBuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());// 新建并返回一个 Retrofit 实例对象,传入上述已经配置好的成员变量returnnewRetrofit(callFactory, baseUrl,unmodifiableList(converterFactories),unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);}}}
Builder.build() 方法,通过已经配置好的成员变量,创建并返回一个 Retrofit 实例对象。至此,Retrofit 实例创建完毕,各项配置也已配置好,接下来通过创建网络请求接口实例,来分析 Retrofit 源码的创建过程。
3. Retrofit 创建网络请求接口实例
这里以最简单的获取用户信息为例,没有结合 RxJava 也没有任何的二次封装,越简单越容易理解。
首先,定义接收网络数据的用户信息类:
publicclassUserInfoBeanimplementsSerializable{privateString user_name;// 用户名privateString user_id;// 用户ID......}
接着,定义网络请求的接口类:
publicinterfaceApi{@GET(“api/userInfo”)// 获取用户信息Observable<UserInfoBean>getUserInfo(@Query("user_id")long user_id);// 请求网络数据的接口方法}
注解 GET:表示使用 Get 方法发送网络请求,括号里面是网络请求的 URL 地址,Retrofit 把网络请求的 URL 分成了两部分:baseUrl 放在创建 Retrofit 对象时设置(参考前面 Retrofit 的构建);另一部分在网络请求接口设置(即这里)。
注意:如果接口里的 URL 是一个完整的网址,那么在创建 Retrofit 实例对象时设置的基地址 baseUrl 可以不设置。
返回值类型是:Observable,UserInfoBean 是解析得到的数据类型,如果不结合 RxJava 使用,则返回值类型是 Call。
最后,使用前面构建的 Retrofit 实例对象,创建接口类实例请求网络数据;
// 传入网络请求的接口类,通过 Retrofit.create() 方法创建网络请求接口的实例对象Api serviceApi = retrofit.create(Api.class);// 由网络请求接口实例对象,对发送请求的信息进行封装,生成最终的网络请求对象Observable<UserInfoBean> userInfo = serviceApi.getUserInfo(user_id);
3.1 Retrofit.create()
publicfinalclassRetrofit{finalboolean validateEagerly;@SuppressWarnings("unchecked")// Single-interface proxy creation guarded by parameter safety.public<T>Tcreate(finalClass<T> service){Utils.validateServiceInterface(service);if(validateEagerly){// 判断是否需要提前验证// eagerlyValidateMethods() 方法的作用是:// 1.给接口中每个方法的注解进行解析并得到一个 ServiceMethod 对象// 2.以 Method 为键将解析得到的对象存入 LinkedHashMap 集合中// 注意:如果不是提前验证则进行动态解析对应方法得到一个 ServiceMethod 对象,最后存入到LinkedHashMap集合中,类似延迟加载(默认)eagerlyValidateMethods(service);}// 创建网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例并返回// 该动态代理是为了拿到网络请求接口实例上所有的注解// 该方法解读为:getProxyClass0(loader, interfaces).getConstructor(constructorParams)// .newInstance(new Object[]{InvocationHandler})return(T)Proxy.newProxyInstance(service.getClassLoader(),newClass<?>[]{ service },newInvocationHandler(){// 将代理类的实现交给 InvocationHandler 类作为具体的实现privatefinalPlatform platform =Platform.get();privatefinalObject[] emptyArgs =newObject[0];// invoke() 方法,执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作// 如统计执行时间、进行初始化和清理、对接口调用进行检查等。@OverridepublicObjectinvoke(Object proxy,Method method,@NullableObject[] args)throwsThrowable{// 如果该方法是 Object 中的方法,则正常调用即可if(method.getDeclaringClass()==Object.class){return method.invoke(this, args);}if(platform.isDefaultMethod(method)){// Android 平台没有重写该方法,因此不支持该操作return platform.invokeDefaultMethod(method, service, proxy, args);}// 由于是接口中的方法,不会走上面两个分支,流程转交给 Retrofit.loadServiceMethod() 方法进行处理// 获取到 ServiceMethod 实例对象后,调用 ServiceMethod.invoke() 方法returnloadServiceMethod(method).invoke(args !=null? args : emptyArgs);}});}// 该方法的主要作用是提前验证指定的方法是不是接口的默认方法,如果不是接口的默认方法,则遍历 service.getDeclaredMethods() // 方法获取到的方法数组,并对其中的每一个 Method 调用 loadServiceMethod() 方法privatevoideagerlyValidateMethods(Class<?> service){Platform platform =Platform.get();for(Method method : service.getDeclaredMethods()){// 检查指定的方法 method 是否是接口的默认方法if(!platform.isDefaultMethod(method)){// 如果不是接口的默认方法,则遍历 service.getDeclaredMethods() 方法获取的方法数组// 对其中的每一个 Method 通过 loadServiceMethod() 方法加载并解析其注解loadServiceMethod(method);}}}}
Retrofit.create() 方法首先判断是否需要提前验证接口中的方法,如果不需要,则通过动态代理创建网络请求接口的实例并返回,通过动态生成的代理类调用 interfaces 接口的方法。实际上是通过调用 InvocationHandler对象的 invoke() 方法来完成指定的功能。也就是当 Api 对象调用 getUserInfo() 接口方法时会进行拦截,调用会集中转发到 InvocationHandler.invoke() 方法进行集中处理,如:接口的统一配置,也就是注解的解析和网络请求参数的拼接。
在 InvocationHandler.invoke() 方法中,由于此时是接口中的方法,不会走上面两个判断分支,因此流程转交给 Retrofit.loadServiceMethod() 方法来获取网络请求接口方法的 ServiceMethod 实例对象,然后继续调用 ServiceMethod.invoke() 方法进行处理。
3.2 Retrofit.loadServiceMethod()
publicfinalclassRetrofit{privatefinalMap<Method,ServiceMethod<?>> serviceMethodCache =newConcurrentHashMap<>();ServiceMethod<?>loadServiceMethod(Method method){// 首先从 serviceMethodCache 缓存中获取方法对应的 ServiceMethodServiceMethod<?> result = serviceMethodCache.get(method);if(result !=null)return result;// 如果不为null,则直接返回该 ServiceMethodsynchronized(serviceMethodCache){// Map 集合中不存在,加锁进行处理,保证方法的唯一性
result = serviceMethodCache.get(method);// 再一次进行获取if(result ==null){// 当前方法依旧不存在// 如果 serviceMethodCache 集合中没有找到对应的 ServiceMethod// 通过 ServiceMethod.parseAnnotations() 方法解析注解获取 ServiceMethod
result =ServiceMethod.parseAnnotations(this, method);// 将解析获取到的 ServiceMethod,以键值对<Method, ServiceMethod>存入 serviceMethodCache 集合中
serviceMethodCache.put(method, result);}}return result;}}
Retrofit.loadServiceMethod() 方法的主要作用是对接口中的指定方法的注解进行解析得到一个 ServiceMethod 对象,其内部通过 ServiceMethod.parseAnnotations() 方法来完成对指定的 Method 方法的注解进行解析,最后将解析获取到的 ServiceMethod,以键值对<Method, ServiceMethod>存入 serviceMethodCache 缓存集合中。
3.3 ServiceMethod.parseAnnotations()
abstractclassServiceMethod<T>{static<T>ServiceMethod<T>parseAnnotations(Retrofit retrofit,Method method){// RequestFactory.parseAnnotations() 方法内部通过 Builder 建造者模式来构建 RequestFactory 实例对象// 对当前方法的所有信息进行解析:方法上的注解、方法参数注解、方法参数值等一系列的解析RequestFactory requestFactory =RequestFactory.parseAnnotations(retrofit, method);// 获取 Method 方法的返回类型Type returnType = method.getGenericReturnType();if(Utils.hasUnresolvableType(returnType)){// 判断返回类型是否是 T 或者 通配符类型throwmethodError(method,"Method return type must not include a type variable or wildcard: %s", returnType);}if(returnType ==void.class){// 返回类型为空 throwmethodError(method,"Service methods cannot return void.");}// 将新建的 RequestFactory 实例和 Retrofit、Method 实例一起转交给 HttpServiceMethod.parseAnnotations() 方法处理returnHttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}abstractTinvoke(Object[] args);}
ServiceMethod 是一个抽象类,既有实体方法也有抽象方法。在其实体方法 parseAnnotations() 中,首先通过 RequestFactory.parseAnnotations() 方法传入 Retrofit 实例和 Method 实例,构建一个 RequestFactory 实例对象,最后将新建的 RequestFactory 实例和 Retrofit、Method 实例一起转交给 HttpServiceMethod.parseAnnotations() 方法处理。
3.3.1 RequestFactory.parseAnnotations()
finalclassRequestFactory{staticRequestFactoryparseAnnotations(Retrofit retrofit,Method method){// 使用建造者模式来构建 RequestFactory 实例对象returnnewBuilder(retrofit, method).build();}RequestFactory(Builder builder){
method = builder.method;// 网络请求方法
baseUrl = builder.retrofit.baseUrl;// 请求基地址
httpMethod = builder.httpMethod;// 请求方式,如:get
relativeUrl = builder.relativeUrl;// 请求相对路径 url
headers = builder.headers;// 请求头数据
contentType = builder.contentType;// 内容类型
hasBody = builder.hasBody;// 是否有请求体
isFormEncoded = builder.isFormEncoded;// 是否是表单提交
isMultipart = builder.isMultipart;// 是否是表单提交(含有文件)
parameterHandlers = builder.parameterHandlers;// 所有参数数据}......staticfinalclassBuilder{finalRetrofit retrofit;// retrofit 实例对象finalMethod method;// 当前网络请求接口方法 finalAnnotation[] methodAnnotations;// 获取当前网络请求方法注解集合 eg:@POSTfinalAnnotation[][] parameterAnnotationsArray;// 当前网络请求方法传入参数的注解集合 eg (@Query("name") String name)finalType[] parameterTypes;// 当前网络请求方法传入参数类型集合 eg (String url) String.class @NullableParameterHandler<?>[] parameterHandlers;Builder(Retrofit retrofit,Method method){this.retrofit = retrofit;this.method = method;this.methodAnnotations = method.getAnnotations();// 获取当前方法传入参数类型集合 eg (String url) String.class // 如果当前数据传入的参数有泛型类型的参数,这个方法可以返回泛型的完整信息 eg:(List<String> list) java.util.List<java.lang.String>// getParameterTypes(); 这个方法仅返回泛型信息 eg:(List<String> list) java.util.Listthis.parameterTypes = method.getGenericParameterTypes();// 获取当前网络请求方法传入参数的注解集合 eg (@Query("name") String name)this.parameterAnnotationsArray = method.getParameterAnnotations();}RequestFactorybuild(){for(Annotation annotation : methodAnnotations){// 遍历网络请求方法上面的注解集合parseMethodAnnotation(annotation);// 解析注解}if(httpMethod ==null){// 请求方式注解是否为nullthrowmethodError(method,"HTTP method annotation is required (e.g., @GET, @POST, etc.).");}if(!hasBody){// 是否有请求体,parseMethodAnnotation 由这个方法体现:DELETE、GET、OPTIONS、HEAD为 falseif(isMultipart){// 没有请求体但是是表单提交(带有文件)throwmethodError(method,"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");}if(isFormEncoded){// 是否是表单提交throwmethodError(method,"FormUrlEncoded can only be specified on HTTP methods with "+"request body (e.g., @POST).");}}int parameterCount = parameterAnnotationsArray.length;// 参数注解数组长度
parameterHandlers =newParameterHandler<?>[parameterCount];// 创建ParameterHandler集合对象for(int p =0; p < parameterCount; p++){// 对参数注解进行逐一解析
parameterHandlers[p]=parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);}......// 实例化请求工厂对象returnnewRequestFactory(this);}}}
RequestFactory.parseAnnotations() 方法内部通过 Builder 建造者模式来构建 RequestFactory 实例对象,通过对当前网络请求方法的所有信息进行解析:方法上的注解、方法参数注解、方法参数值等一系列的解析后保存起来。
3.4 HttpServiceMethod.parseAnnotations()
/** Adapts an invocation of an interface method into an HTTP call. */// 将接口方法的调用适配为 HTTP 调用finalclassHttpServiceMethod<ResponseT,ReturnT>extendsServiceMethod<ReturnT>{// 检查接口方法上的注释,以构造一个可重复使用的 HTTP 服务方法// 由于要用到反射,开销较大,因此每个服务方法只构建一次然后重用它static<ResponseT,ReturnT>HttpServiceMethod<ResponseT,ReturnT>parseAnnotations(Retrofit retrofit,Method method,RequestFactory requestFactory){// 通过 createCallAdapter() 方法创建 CallAdapter 实例对象CallAdapter<ResponseT,ReturnT> callAdapter =createCallAdapter(retrofit, method);Type responseType = callAdapter.responseType();// 获取响应数据类型 if(responseType ==Response.class|| responseType ==okhttp3.Response.class){throwmethodError(method,"'"+Utils.getRawType(responseType).getName()+"' is not a valid response body type. Did you mean ResponseBody?");}// 请求方法是请求头 并且方法返回不为 Voidif(requestFactory.httpMethod.equals("HEAD")&&!Void.class.equals(responseType)){throwmethodError(method,"HEAD method must use Void as response type.");}// 通过 createResponseConverter() 方法创建 Converter 实例对象用于解析服务端返回的数据Converter<ResponseBody,ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);// callFactory 就是开始初始化的 OkHttpClientokhttp3.Call.Factory callFactory = retrofit.callFactory;// 使用入参以及上面获取的几个实例对象,新建 HttpServiceMethod 实例对象returnnewHttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);}}
HttpServiceMethod.parseAnnotations() 方法,首先通过 createCallAdapter() 方法创建 CallAdapter 实例对象,然后通过 createResponseConverter() 方法创建 Converter 实例对象用于解析服务端返回的数据,最后使用入参以及上面获取的几个实例对象,新建 HttpServiceMethod 实例对象。
3.4.1 HttpServiceMethod.createCallAdapter()
/** Adapts an invocation of an interface method into an HTTP call. */// 将接口方法的调用适配为 HTTP 调用finalclassHttpServiceMethod<ResponseT,ReturnT>extendsServiceMethod<ReturnT>{......privatestatic<ResponseT,ReturnT>CallAdapter<ResponseT,ReturnT>createCallAdapter(Retrofit retrofit,Method method){Type returnType = method.getGenericReturnType();// 获取网络请求接口里方法的返回值类型Annotation[] annotations = method.getAnnotations();// 获取网络请求接口里的注解,示例代码中是 @GETtry{// 根据获取的 returnType 和 annotations,通过 retrofit.callAdapter() 方法获取 CallAdapterreturn(CallAdapter<ResponseT,ReturnT>) retrofit.callAdapter(returnType, annotations);}catch(RuntimeException e){// Wide exception range because factories are user code.throwmethodError(method, e,"Unable to create call adapter for %s", returnType);}}}
HttpServiceMethod.createCallAdapter() 方法的主要作用是,根据获取的网络请求接口方法的返回值类型 returnType 和 annotations 注解,通过 Retrofit.callAdapter() 方法从 Retrofit 对象中获取对应的网络请求适配器 CallAdapter 实例对象。
3.4.2 Retrofit.callAdapter()
publicfinalclassRetrofit{finalList<CallAdapter.Factory> callAdapterFactories;// 从可用的 callAdapterFactories 工厂集合中返回指定 returnType 的 CallAdapter 实例对象// 构造 Retrofit 实例对象时进行添加的 CallAdapter.FactorypublicCallAdapter<?,?>callAdapter(Type returnType,Annotation[] annotations){// 继续调用 nextCallAdapter() 方法来获取 CallAdapter 实例对象returnnextCallAdapter(null, returnType, annotations);}// 从可用的 callAdapterFactories 工厂集合中(skipPast 除外)返回指定 returnType 的 CallAdapter 实例对象publicCallAdapter<?,?>nextCallAdapter(@NullableCallAdapter.Factory skipPast,Type returnType,Annotation[] annotations){checkNotNull(returnType,"returnType == null");checkNotNull(annotations,"annotations == null");int start = callAdapterFactories.indexOf(skipPast)+1;for(int i = start, count = callAdapterFactories.size(); i < count; i++){// 遍历 callAdapterFactories 集合寻找对应的工厂,进而再找出符合条件的 CallAdapter 并返回// 由于构造 Retroifit 实例对象时添加的是 RxJava2CallAdapterFactory,因此这里获取到的就是 RxJava2CallAdapterFactory 工厂// 由 RxJava2CallAdapterFactory.get()方法根据网络请求接口方法的返回值类型和注解,返回符合条件的 RxJava2CallAdapter 实例对象CallAdapter<?,?> adapter = callAdapterFactories.get(i).get(returnType, annotations,this);if(adapter !=null){return adapter;}}// 如果最终没有找到工厂来提供需要的 CallAdapter,则拼接并抛出异常信息StringBuilder builder =newStringBuilder("Could not locate call adapter for ").append(returnType).append(".\n");if(skipPast !=null){
builder.append(" Skipped:");for(int i =0; i < start; i++){
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());}
builder.append('\n');}
builder.append(" Tried:");for(int i = start, count = callAdapterFactories.size(); i < count; i++){
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());}thrownewIllegalArgumentException(builder.toString());}}
Retrofit.callAdapter() 方法将获取指定 returnType 和 annotations 注解的 CallAdapter 实例对象的任务转交给 Retrofit.nextCallAdapter() 方法进行查找,找到符合条件的 CallAdapter 实例对象则直接返回,否者抛出报错信息。
3.4.3 HttpServiceMethod.createResponseConverter()
/** Adapts an invocation of an interface method into an HTTP call. */// 将接口方法的调用适配为 HTTP 调用finalclassHttpServiceMethod<ResponseT,ReturnT>extendsServiceMethod<ReturnT>{......privatestatic<ResponseT>Converter<ResponseBody,ResponseT>createResponseConverter(Retrofit retrofit,Method method,Type responseType){Annotation[] annotations = method.getAnnotations();try{// 根据入参 responseType 及获取的 annotations,通过 retrofit.responseBodyConverter() 方法获取 Converterreturn retrofit.responseBodyConverter(responseType, annotations);}catch(RuntimeException e){// Wide exception range because factories are user code.throwmethodError(method, e,"Unable to create converter for %s", responseType);}}}
HttpServiceMethod.createResponseConverter() 方法的主要作用是,根据入参 responseType 及获取的方法的 annotations 注解,通过 retrofit.responseBodyConverter() 方法从 Retrofit 对象中获取对应的数据转换器 Converter 实例对象。
3.4.4 Retrofit.responseBodyConverter()
publicfinalclassRetrofit{finalList<Converter.Factory> converterFactories;// 从可用的 converterFactories 工厂集合中为 ResponseBody 找到指定 type 的 Converter 实例对象// 构造 Retrofit 实例对象时进行添加的 Converter.Factorypublic<T>Converter<ResponseBody,T>responseBodyConverter(Type type,Annotation[] annotations){returnnextResponseBodyConverter(null, type, annotations);}// 从可用的 converterFactories 工厂集合中为 ResponseBody 找到指定 type 的 Converter 实例对象(除了 skipPast)public<T>Converter<ResponseBody,T>nextResponseBodyConverter(@NullableConverter.Factory skipPast,Type type,Annotation[] annotations){checkNotNull(type,"type == null");checkNotNull(annotations,"annotations == null");int start = converterFactories.indexOf(skipPast)+1;for(int i = start, count = converterFactories.size(); i < count; i++){// 遍历 converterFactories 集合寻找对应的工厂,进而再找出符合条件的 Converter 并返回// 由于构造 Retroifit 实例对象时采用的是 Gson 解析方式,所以先取出的是 GsonConverterFactory 工厂// 由 GsonConverterFactory.responseBodyConverter()方法根据 responseType 类型和注解// 返回符合条件的 GsonResponseBodyConverter 实例对象Converter<ResponseBody,?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations,this);if(converter !=null){//noinspection uncheckedreturn(Converter<ResponseBody,T>) converter;}}// 如果最终没有找到工厂来提供需要的 Converter,则拼接并抛出异常信息StringBuilder builder =newStringBuilder("Could not locate ResponseBody converter for ").append(type).append(".\n");if(skipPast !=null){
builder.append(" Skipped:");for(int i =0; i < start; i++){
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());}
builder.append('\n');}
builder.append(" Tried:");for(int i = start, count = converterFactories.size(); i < count; i++){
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());}thrownewIllegalArgumentException(builder.toString());}}
Retrofit.responseBodyConverter() 方法将为 ResponseBody 获取指定 type 的 Converter 实例对象的任务转交给 Retrofit.nextResponseBodyConverter() 方法进行查找,找到符合条件的 Converter 实例对象则直接返回,否者抛出报错信息。
3.4.5 GsonConverterFactory.responseBodyConverter()
publicfinalclassGsonConverterFactoryextendsConverter.Factory{privatefinalGson gson;privateGsonConverterFactory(Gson gson){this.gson = gson;}@OverridepublicConverter<ResponseBody,?>responseBodyConverter(Type type,Annotation[] annotations,Retrofit retrofit){// 根据目标类型,利用 Gson.getAdapter() 方法获取相应的 adapterTypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));// 使用创建 GsonConverterFactory 时保存的 gson 实例和 adapter 新建 GsonResponseBodyConverter 实例对象returnnewGsonResponseBodyConverter<>(gson, adapter);}}
GsonConverterFactory.responseBodyConverter() 方法中根据目标类型,利用 Gson.getAdapter() 方法获取相应的 adapter,随后使用创建 GsonConverterFactory 时保存的 gson 实例和 adapter 新建 GsonResponseBodyConverter 实例对象。
3.4.6 GsonResponseBodyConverter
finalclassGsonResponseBodyConverter<T>implementsConverter<ResponseBody,T>{// 用于数据解析的主要类,内部采用工厂设计模式来实现不同 TypeAdapter 的创建,其成员变量fatories保存了// TypeAdapterFactory 列表,成员函数 getAdapter(type) 方法则根据不同的 type 去匹配 factories 中的一个工厂类,// 然后调用该工厂类的 create() 方法得到一个相应的 TypeAdapter 对象privatefinalGson gson;privatefinalTypeAdapter<T> adapter;// TypeAdapter是一个抽象类,定义了转换的顶层接口,具体功能是在其子类中实现的GsonResponseBodyConverter(Gson gson,TypeAdapter<T> adapter){this.gson = gson;this.adapter = adapter;}@OverridepublicTconvert(ResponseBody value)throwsIOException{// 通过 gson.newJsonReader() 方法新建 JsonReader 实例对象,将服务端返回的 Json 数据以流的形式读入JsonReader jsonReader = gson.newJsonReader(value.charStream());try{// TypeAdapter.read() 方法将 Json 数据流解析成结构化对象T,其内部是通过 fromJson()方法T result = adapter.read(jsonReader);if(jsonReader.peek()!=JsonToken.END_DOCUMENT){thrownewJsonIOException("JSON document was not fully consumed.");}return result;}finally{
value.close();}}}
GsonResponseBodyConverter 类实现了 Converter 接口,在其实现的 convert() 方法中,首先通过 gson.newJsonReader() 方法新建 JsonReader 实例对象,将服务端返回的 Json 数据以流的形式读入,然后通过 TypeAdapter.read() 方法将 Json 数据流解析成结构化对象 T 并返回,其内部是通过 fromJson()方法实现的。
HttpServiceMethod.parseAnnotations() 方法的最后根据入参以及上面获取的几个实例对象,新建 HttpServiceMethod 实例对象并返回给代理对象 InvocationHandler.invoke() 方法最后调用的 Retrofit.loadServiceMethod() 方法,进而继续调用 HttpServiceMethod.invoke() 方法。
3.5 HttpServiceMethod
/** Adapts an invocation of an interface method into an HTTP call. */// 将接口方法的调用适配为 HTTP 调用finalclassHttpServiceMethod<ResponseT,ReturnT>extendsServiceMethod<ReturnT>{......privatefinalRequestFactory requestFactory;// 解析注解构造的请求工厂数据,里面有method,baseUrl,httpMethod等privatefinalokhttp3.Call.Factory callFactory;// 默认为 OkHttpClient 对象privatefinalCallAdapter<ResponseT,ReturnT> callAdapter;// 用于适配 OkHttpCall 的网络请求适配器privatefinalConverter<ResponseBody,ResponseT> responseConverter;// 用于解析响应的数据转换器 Converter // 构建 HttpServiceMethod 的实例对象,并保存入参到其成员变量中privateHttpServiceMethod(RequestFactory requestFactory,okhttp3.Call.Factory callFactory,CallAdapter<ResponseT,ReturnT> callAdapter,Converter<ResponseBody,ResponseT> responseConverter){this.requestFactory = requestFactory;this.callFactory = callFactory;this.callAdapter = callAdapter;this.responseConverter = responseConverter;}@OverrideReturnTinvoke(Object[] args){// 由前面的分析可知,这里调用的是 RxJava2CallAdapter.adapt() 方法,并新建 OkHttpCall 实例对象作为方法的入参return callAdapter.adapt(newOkHttpCall<>(requestFactory, args, callFactory, responseConverter));}}
HttpServiceMethod 是抽象类 ServiceMethod 的具体实现,用来存储一次网络请求的基本信息,比如:Host、URL、请求方法等,还会存储用来适配 OkHttpCall 对象的 CallAdapter、用来创建网络请求 Call 的 Call.Factory、用来进行数据解析的数据转换器 Converter 以及用来构建网络请求 Request 的 RequestFactory 等实例对象。
构建完 HttpServiceMethod 实例对象后,调用其 invoke() 方法并传入网络请求接口的参数,在其 invoke() 方法中首先将前面配置好的 RequestFactory、Call.Factory、Converter 以及输入的网络请求接口的参数构建 OkHttpCall 实例对象,然后将构建的 OkHttpCall 实例对象作为入参传给 RxJava2CallAdapter.adapt() 方法进行下一步的处理。
3.6 OkHttpCall
finalclassOkHttpCall<T>implementsCall<T>{privatefinalRequestFactory requestFactory;privatefinalObject[] args;privatefinalokhttp3.Call.Factory callFactory;privatefinalConverter<ResponseBody,T> responseConverter;OkHttpCall(RequestFactory requestFactory,Object[] args,okhttp3.Call.Factory callFactory,Converter<ResponseBody,T> responseConverter){this.requestFactory = requestFactory;// 网络请求 RequestFactory 工厂 this.args = args;// 网络请求接口的参数this.callFactory = callFactory;// 网络请求 Call 工厂this.responseConverter = responseConverter;// 数据转换器}}
OkHttpCall 是 Retrofit 库中接口 Call 的一个实现类,其入参就是前面配置好的网络请求会用到的一些资源,实现了接口 Call 的几个重要方法:
- **execute()**:表示同步请求,返回值就是网络请求结果;
- **enqueue(Callback<T> callback)**:表示异步请求,返回值需要通过 Callback 回调来获取;
- **request()**:表示创建一个请求,返回 Request 类型。
3.7 RxJava2CallAdapter.adapt()
finalclassRxJava2CallAdapterimplementsCallAdapter<Object>{privatefinalType responseType;@OverridepublicTyperesponseType(){return responseType;}@Overridepublic<R>Objectadapt(Call<R> call){// 使用入参 OkHttpCall 对象构建 CallObservable 实例对象,后续根据不同的条件新建或转换为符合要求的 ObservableObservable<Response<R>> responseObservable =newCallObservable<>(call);Observable<?> observable;if(isResult){
observable =newResultObservable<>(responseObservable);}elseif(isBody){// 参考 2.6.1 RxJava2CallAdapterFactory.create()的分析,isBody 为 true
observable =newBodyObservable<>(responseObservable);}else{
observable = responseObservable;}if(scheduler !=null){// 如果设置了 scheduler 则需建立订阅关系
observable = observable.subscribeOn(scheduler);}// Flowable 能够发射0或n个数据,并以成功或者错误事件终止。支持背压,可以控制数据源发射的速度if(isFlowable){// 如果是 Flowable,则将 Observable 转换为 Flowablereturn observable.toFlowable(BackpressureStrategy.LATEST);}if(isSingle){// 如果是 Single,则将 Observable 转换为 Single,Single 只发射单个数据或者错误事件return observable.singleOrError();}// Maybe 能够发射0或者1个数据,要么成功,要么失败。有点类似于 Optionalif(isMaybe){// 如果是 Maybe,则将 Observable 转换为 Maybereturn observable.singleElement();}// Completable 从来不发射数据,只处理onComplete和onError事件。可以看成 Rx 的 Runnableif(isCompletable){// 如果是 Completable,则将 Observable 转换为 Completablereturn observable.ignoreElements();}return observable;}}
RxJava2CallAdapter.adapt() 方法经过判断处理得到所需的可以操作的 Observable 网络请求对象,由于这里只是简单的使用,没有特殊要求的情况下返回的是 BodyObservable 对象。
问题:为什么 InvocationHandler.invoke() 方法不可以直接返回 OKHttpCall 对象,而是调用 CallAdapter.adapt(call, args) 方法进行适配器适配?
答:想象一下,如果没有适配器的话,网络请求返回接口只能直接返回 OkHttpCall,且所有的网络请求都是用 OkHttpCall 进行,这样就失去了 Retrofit 封装的意义,也不够灵活,如:RxJava 的 Observable 就无法支持。而采用适配器模式,将网络请求的核心类 OkHttpCall 进行适配,可根据实际需要通过适配器的适配返回适配后的对象,使得用户在使用 Retrofit 的时候可以自定义想要的返回类型。
小结
Retrofit 采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体细节是:
- 通过动态代理模式来动态的创建网络请求接口的实例对象 HttpServiceMethod;
- 通过 Retrofit.loadServiceMethod() 方法从 serviceMethodCache 缓存队列中获取 HttpServiceMethod 实例对象,如缓存中已有对应的实例对象,则直接返回(缓存机制,避免重复解析创建);
- 如果缓存中没有则由 ServiceMethod.parseAnnotations() 解析注解获得,通过解析网络请求接口方法的参数、返回值类型和注解,从 Retrofit 对象中获取对应的网络请求的 URL 地址、网络请求执行器、网络请求适配器及数据转换器(策略模式);
- 构建 HttpServiceMethod 实例对象,保存前面解析获取到的网络请求所需的必要信息,并把新建的 HttpServiceMethod 实例对象添加到 serviceMethodCache 缓存队列中;
- 调用 HttpServiceMethod.invoke() 方法,通过适配的 RxJava2CallAdapter.adapt() 方法,传入新建的 OkHttpCall 实例对象,最终创建并返回一个 Observable 类型的网络请求对象 BodyObservable。
4. Retrofit 执行网络请求
经过前面几节的分析,Retrofit 实例对象和 Observable 类型的网络请求对象都已创建完,那怎么来执行网络请求呢?
接下来为了更好的理解 Retrofit 的网络请求执行流程,对 Retrofit 进行了简单的封装以便于更好的理解其与 RxJava 的结合使用,示例代码如下:
RetrofitManager.getInstance()// 获取 Retrofit 实例对象.getNetService(Api.class)// 内部通过 Retrofit.create() 方法创建网络请求接口的实例对象.getUserInfo()// 通过网络请求接口的实例对象,对请求的参数等信息进行封装,生成最终的网络请求对象 Observable<UserInfoBean>.subscribeOn(Schedulers.io())// 指定被观察者 Observable 是在 Schedulers.io() 线程执行操作.observeOn(AndroidSchedulers.mainThread())// 指定观察者 Observer在 AndroidSchedulers.mainThread(),即 Android主线程上执行操作,以更新UI.subscribe(newObserver<UserInfoBean>(){// 构建观察者 Observer 实例对象,通过 subscribe() 完成订阅,此时被观察者 Observable 开始向观察者发送数据@OverridepublicvoidonSubscribe(Disposable d){// 订阅时的操作 }@OverridepublicvoidonNext(UserInfoBean userInfo){// UI界面展示获取到的用户信息}@OverridepublicvoidonError(Throwable e){// 出错时的操作 }@OverridepublicvoidonComplete(){// 完成时的操作 }});
被观察者 Observable 和观察者 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
4.1 Observable.subscribe()
publicabstractclassObservable<T>implementsObservableSource<T>{@SchedulerSupport(SchedulerSupport.NONE)@Overridepublicfinalvoidsubscribe(Observer<?superT> observer){ObjectHelper.requireNonNull(observer,"observer is null");try{// RxJava 提供的一个钩子方法,用于在 Observable 被订阅时进行一些自定义的逻辑处理// 你可以通过实现该方法来拦截所有的 subscribe 调用,并对其进行相应的处理
observer =RxJavaPlugins.onSubscribe(this, observer);ObjectHelper.requireNonNull(observer,"The RxJavaPlugins.onSubscribe hook returned a null Observer. Please change the handler provided to RxJavaPlugins.setOnObservableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");// 继续调用 subscribeActual()subscribeActual(observer);}catch(NullPointerException e){// NOPMDthrow e;}catch(Throwable e){Exceptions.throwIfFatal(e);// can't call onError because no way to know if a Disposable has been set or not// can't call onSubscribe because the call might have set a Subscription alreadyRxJavaPlugins.onError(e);NullPointerException npe =newNullPointerException("Actually not, but can't throw other exceptions due to RS");
npe.initCause(e);throw npe;}}}
Observable.subscribe() 方法中继续调用其 subscribeActual() 方法,看名字应该是真正用来订阅的,但其实这是一个抽象方法,在前面获取到的 BodyObservable 继承自 Observable 并实现了该方法。
4.2 BodyObservable.subscribeActual()
finalclassBodyObservable<T>extendsObservable<T>{privatefinalObservable<Response<T>> upstream;// 创建 BodyObservable 时传入的是 CallObservable 实例对象BodyObservable(Observable<Response<T>> upstream){this.upstream = upstream;}@OverrideprotectedvoidsubscribeActual(Observer<?superT> observer){// 这里转调 CallObservable.subscribe() 方法
upstream.subscribe(newBodyObserver<>(observer));}
BodyObservable.subscribeActual() 方法继续转调 CallObservable.subscribe() 方法,CallObservable 本身没有 subscribe() 方法,因此调用的是其父类 Observable.subscribe() 方法,最后流程转调到 CallObservable.subscribeActual() 方法。
4.3 CallObservable.subscribeActual()
finalclassCallObservable<T>extendsObservable<Response<T>>{privatefinalCall<T> originalCall;CallObservable(Call<T> originalCall){this.originalCall = originalCall;}@OverrideprotectedvoidsubscribeActual(Observer<?superResponse<T>> observer){// 为每个新的观察者克隆 originalCall 的副本Call<T> call = originalCall.clone();
observer.onSubscribe(newCallDisposable(call));// 开始执行onSubscribe方法boolean terminated =false;try{// 请求开始执行,会进行阻塞Response<T> response = call.execute();if(!call.isCanceled()){// 请求未被取消,拿到数据之后,执行onNext()方法发送数据
observer.onNext(response);}if(!call.isCanceled()){// 未被取消,则执行完成
terminated =true;
observer.onComplete();}}catch(Throwable t){Exceptions.throwIfFatal(t);if(terminated){RxJavaPlugins.onError(t);// 执行异常方法}elseif(!call.isCanceled()){try{
observer.onError(t);}catch(Throwable inner){Exceptions.throwIfFatal(inner);RxJavaPlugins.onError(newCompositeException(t, inner));}}}}}
CallObservable.subscribeActual() 方法的执行流程如下:
- 通过 call.execute() 方法执行请求,此处 Call 是在执行 RxJava2CallAdapter.adapt() 方法时传进来的。因此这里调用的是 Call 的实现类 OkHttpCall.execute() 方法;
- 请求未取消,且成功拿到数据之后,执行 Observer.onNext() 方法向观察者发送数据,即 UI 界面获取到数据并展示获取到的信息。
4.4 OkHttpCall.execute()
finalclassOkHttpCall<T>implementsCall<T>{@GuardedBy("this")[email protected] rawCall;@GuardedBy("this")// Either a RuntimeException, non-fatal Error, or IOException.private@NullableThrowable creationFailure;@GuardedBy("this")privateboolean executed;@OverridepublicResponse<T>execute()throwsIOException{okhttp3.Call call;synchronized(this){// 加锁处理,防止重复执行当前请求if(executed)thrownewIllegalStateException("Already executed.");
executed =true;if(creationFailure !=null){// 创建 RealCall 失败,出现了异常,进行处理if(creationFailure instanceofIOException){throw(IOException) creationFailure;}elseif(creationFailure instanceofRuntimeException){throw(RuntimeException) creationFailure;}else{throw(Error) creationFailure;}}
call = rawCall;if(call ==null){// 第一次执行时为nulltry{
call = rawCall =createRawCall();// 创建一个 RealCall}catch(IOException|RuntimeException|Error e){throwIfFatal(e);// Do not assign a fatal error to creationFailure.
creationFailure = e;throw e;}}}if(canceled){
call.cancel();}// 执行网络请求并解析响应returnparseResponse(call.execute());}privateokhttp3.CallcreateRawCall()throwsIOException{// 这里 callFactory 就是之前 Retrofit 初始化时添加的 OkHttpClientokhttp3.Call call = callFactory.newCall(requestFactory.create(args));if(call ==null){thrownewNullPointerException("Call.Factory returned null.");}return call;}}
OkHttpCall.execute() 方法中,首先调用 createRawCall() 方法创建一个 RealCall,随后调用 RealCall.execute() 方法执行网络请求,最后调用 parseResponse() 方法解析网络请求响应。
4.4.1 RequestFactory.create()
finalclassRequestFactory{privatefinalParameterHandler<?>[] parameterHandlers;......okhttp3.Requestcreate(Object[] args)throwsIOException{@SuppressWarnings("unchecked")// It is an error to invoke a method with the wrong arg types.ParameterHandler<Object>[] handlers =(ParameterHandler<Object>[]) parameterHandlers;int argumentCount = args.length;if(argumentCount != handlers.length){thrownewIllegalArgumentException("Argument count ("+ argumentCount
+") doesn't match expected count ("+ handlers.length +")");}// 使用构建 RequestFactory 实例时保存的网络请求所需的必要参数来构建 RequestBuilder 实例对象RequestBuilder requestBuilder =newRequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);// 对网络请求接口方法中的每个参数利用对应的 ParameterHandler 进行解析List<Object> argumentList =newArrayList<>(argumentCount);for(int p =0; p < argumentCount; p++){
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);}// 最后通过 RequestBuilder 建造者模式构建 Request 实例对象return requestBuilder.get().tag(Invocation.class,newInvocation(method, argumentList)).build();}}
RequestFactory.create() 方法首先使用构建 RequestFactory 实例时保存的网络请求所需的必要参数来构建 RequestBuilder 实例对象,随后通过 RequestBuilder 建造者模式构建 Request 实例对象。
4.4.2 OkHttpClient.newCall()
publicclassOkHttpClientimplementsCloneable,Call.Factory,WebSocket.Factory{......publicCallnewCall(Request request){returnRealCall.newRealCall(this, request,false);}}
OkHttpClient.newCall() 方法继续调用 RealCall.newRealCall() 方法创建 RealCall 实例对象并返回。
4.4.3 RealCall.newRealCall()
finalclassRealCallimplementsCall{finalOkHttpClient client;privateTransmitter transmitter;finalRequest originalRequest;finalboolean forWebSocket;privateboolean executed;privateRealCall(OkHttpClient client,Request originalRequest,boolean forWebSocket){this.client = client;this.originalRequest = originalRequest;this.forWebSocket = forWebSocket;}staticRealCallnewRealCall(OkHttpClient client,Request originalRequest,boolean forWebSocket){RealCall call =newRealCall(client, originalRequest, forWebSocket);
call.transmitter =newTransmitter(client, call);return call;}}
RealCall 是 OkHttp 库中 Call 的实现类,实现了 Call 接口内部定义的同步与异步请求、取消请求等方法。在 RealCall.newRealCall() 方法中,首先根据入参创建 RealCall 实例对象,然后使用新建的 RealCall 和 OkHttpClient 自身来新建 Transmitter 实例对象并赋值给 RealCall.transmitter 成员变量,最后返回刚创建的 RealCall 实例对象。
OkHttp 后面的代码本文不再深入,后续写文章深入剖析,现在已经获取到 RealCall 实例对象,并调用 RealCall.execute() 方法,后续会通过 RealCall 的拦截器链层层调用后,再一步步返回请求响应 Response,也就是说现在已经获取到网络请求返回的 Response,接下来分析 Retrofit 是如何解析请求响应的。
4.5 OkHttpCall.parseResponse()
finalclassOkHttpCall<T>implementsCall<T>{Response<T>parseResponse(okhttp3.Response rawResponse)throwsIOException{ResponseBody rawBody = rawResponse.body();// 拿到返回过来的响应体// Remove the body's source (the only stateful object) so we can pass the response along.// 移除 Response 的响应体 ResponseBody(唯一有状态的对象),这样我们就可以传递响应
rawResponse = rawResponse.newBuilder()// Response 设置没有内容的 NoContentResponseBody.body(newNoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();int code = rawResponse.code();// 响应码if(code <200|| code >=300){// 响应异常情况try{// 缓冲整个主体以避免将来的 I/O 操作ResponseBody bufferedBody =Utils.buffer(rawBody);returnResponse.error(bufferedBody, rawResponse);// 将请求异常的情况进行返回}finally{
rawBody.close();}}if(code ==204|| code ==205){// 请求成功情况,只是返回数据为null
rawBody.close();returnResponse.success(null, rawResponse);}ExceptionCatchingResponseBody catchingBody =newExceptionCatchingResponseBody(rawBody);try{// 转换器 Converter 转换 Response 的 ResponseBodyT body = responseConverter.convert(catchingBody);// 调用 Response.success() 方法构建一个新的 Response 并返回 returnResponse.success(body, rawResponse);}catch(RuntimeException e){// If the underlying source threw an exception, propagate that rather than indicating it was// a runtime exception.
catchingBody.throwIfCaught();throw e;}}}
OkHttpCall.parseResponse() 方法首先获取 Response 的 ResponseBody 响应体,调用 responseConverter.convert() 方法对 ResponseBody 响应体进行数据转换,最后调用 Response.success() 方法构建一个新的 Response 并返回。
4.5.1 GsonResponseBodyConverter.convert()
finalclassGsonResponseBodyConverter<T>implementsConverter<ResponseBody,T>{// 用于数据解析的主要类,内部采用工厂设计模式来实现不同 TypeAdapter 的创建,其成员变量fatories保存了// TypeAdapterFactory 列表,成员函数 getAdapter(type) 方法则根据不同的 type 去匹配 factories 中的一个工厂类,// 然后调用该工厂类的 create() 方法得到一个相应的 TypeAdapter 对象privatefinalGson gson;privatefinalTypeAdapter<T> adapter;// TypeAdapter是一个抽象类,定义了转换的顶层接口,具体功能是在其子类中实现的GsonResponseBodyConverter(Gson gson,TypeAdapter<T> adapter){this.gson = gson;this.adapter = adapter;}@OverridepublicTconvert(ResponseBody value)throwsIOException{// 通过 gson.newJsonReader() 方法新建 JsonReader 实例对象,将服务端返回的 Json 数据以流的形式读入JsonReader jsonReader = gson.newJsonReader(value.charStream());try{// TypeAdapter.read() 方法将 Json 数据流解析成结构化对象T,其内部是通过 fromJson()方法// 此处 adapter 是 GsonConverterFactory.responseBodyConverter() 方法中由 Gson.getAdapter()方法获取的T result = adapter.read(jsonReader);if(jsonReader.peek()!=JsonToken.END_DOCUMENT){thrownewJsonIOException("JSON document was not fully consumed.");}return result;}finally{
value.close();}}}
GsonResponseBodyConverter 类在前面分析过,在其实现的 convert() 方法中,首先通过 gson.newJsonReader() 方法新建 JsonReader 实例对象,将服务端返回的 Json 数据以流的形式读入,然后通过 TypeAdapter.read() 方法将 Json 数据流解析成结构化对象 T 并返回,其内部是通过 fromJson()方法实现的。
4.5.2 Gson.getAdapter()
publicfinalclassGson{@SuppressWarnings("unchecked")public<T>TypeAdapter<T>getAdapter(TypeToken<T> type){// 获取 Map<TypeToken<?>, TypeAdapter<?>> 缓存中的请求 adapter 是否存在,存在即返回 TypeAdapter<?> cached = typeTokenCache.get(type ==null?NULL_KEY_SURROGATE: type);if(cached !=null){return(TypeAdapter<T>) cached;}// 本地线程缓冲中获取当前线程的请求数据信息Map<TypeToken<?>,FutureTypeAdapter<?>> threadCalls = calls.get();boolean requiresThreadLocalCleanup =false;// 是否清除本地线程缓冲数据if(threadCalls ==null){// 本地线程缓冲中不存在
threadCalls =newHashMap<TypeToken<?>,FutureTypeAdapter<?>>();// 实例化一个 HashMap
calls.set(threadCalls);// 缓存至 TLB 中
requiresThreadLocalCleanup =true;// 进行清除}// 键和值类型参数始终一致FutureTypeAdapter<T> ongoingCall =(FutureTypeAdapter<T>) threadCalls.get(type);// 获取当前返回类型的FutureTypeAdapter适配器if(ongoingCall !=null){// 已经存在当前返回值的适配器则直接返回return ongoingCall;}try{// 当前 FutureTypeAdapter 适配器依旧为null,创建一个适配器FutureTypeAdapter<T> call =newFutureTypeAdapter<T>();
threadCalls.put(type, call);// 并将当前适配器与对应的 type 保存到 HashMap 中// 在 Gson 初始化的 List<TypeAdapterFactory> 中遍历查找对应的 TypeAdapterfor(TypeAdapterFactory factory : factories){// 获取到解析适配器TypeAdapter<T> candidate = factory.create(this, type);if(candidate !=null){
call.setDelegate(candidate);// 设置参数
typeTokenCache.put(type, candidate);// 存入缓存 Map<TypeToken<?>, TypeAdapter<?>> 集合中return candidate;}}thrownewIllegalArgumentException("GSON cannot handle "+ type);}finally{
threadCalls.remove(type);if(requiresThreadLocalCleanup){
calls.remove();}}}}
Gson.getAdapter() 方法查找并获取指定类型映射的 TypeAdapter 实例对象,TypeAdapter 是一个抽象类,其 read() 方法在不同子类中实现的方式也不一样,这里以 ReflectiveTypeAdapterFactory 类的内部类 Adapter 为例,其继承自 TypeAdapter 类并实现其 read() 方法。
4.5.3 ReflectiveTypeAdapterFactory.Adapter.read()
publicfinalclassReflectiveTypeAdapterFactoryimplementsTypeAdapterFactory{......publicstaticfinalclassAdapter<T>extendsTypeAdapter<T>{privatefinalObjectConstructor<T> constructor;privatefinalMap<String,BoundField> boundFields;@OverridepublicTread(JsonReader in)throwsIOException{if(in.peek()==JsonToken.NULL){// 得到 JsonToken.NULL 则不进入当前判断
in.nextNull();returnnull;}T instance = constructor.construct();// 初始化实例操作try{
in.beginObject();// 开始解析对象while(in.hasNext()){// 是否有下一个,第一次到这里,返回 PEEKED_DOUBLE_QUOTED_NAME trueString name = in.nextName();// 获取 name 信息BoundField field = boundFields.get(name);// 根据集合去获取里面的字段信息if(field ==null||!field.deserialized){// 如果字段为 null 或字段不能反序列化
in.skipValue();// 跳过value值,因为解析的类对象中不存在当前字段或者这个字段不能反序列化}else{
field.read(in, instance);// 开始执行,根据字段类型去读取 value 值}}}catch(IllegalStateException e){thrownewJsonSyntaxException(e);}catch(IllegalAccessException e){thrownewAssertionError(e);}
in.endObject();return instance;}}}
限于篇幅 Retrofit 后续解析过程本文不再继续深入,在通过数据转换器 GsonResponseBodyConverter.convert() 方法对 ResponseBody 响应体进行数据解析转换后,最后会调用 Response.success() 方法构建一个新的 Response 并返回。
4.6 Response.success()
publicfinalclassResponse<T>{// 由 rawResponse 和 body 创建一个成功的 Response 作为反序列化的 bodypublicstatic<T>Response<T>success(@NullableT body,okhttp3.Response rawResponse){checkNotNull(rawResponse,"rawResponse == null");if(!rawResponse.isSuccessful()){thrownewIllegalArgumentException("rawResponse must be successful response");}// 判空并检查是成功的,则重新构建 okhttp3.Response 响应returnnewResponse<>(rawResponse, body,null);}}
Response.success() 方法中,由 rawResponse 和 body 创建一个成功的 Response 响应作为反序列化的 body 并返回。
此时,回到 4.3 CallObservable.subscribeActual() 方法,如果请求未取消,且成功拿到数据之后,执行 Observer.onNext() 方法向观察者发送数据,即 UI 界面获取到数据并展示获取到的信息。流程至此,Retrofit 的请求及解析过程也剖析完毕,当然里面还有很多细节,在一篇文章中是很难剖析完全的,感兴趣的可以再深入跟一下,后续有时间,笔者也会继续剖析。
小结
Retrofit 结合 RxJava 来实现网络请求是目前比较常见的异步编程模式,可以提高网络请求的效率和响应速度。
- Retrofit 创建 Observable 网络请求对象后,使用该对象发送网络请求的结果;
- Retrofit 使用 OkHttp 的 Request 发送网络请求,网络请求最终是通过 OkHttp 内部的 RealCall 来执行,经过其拦截器链层层调用后,再一步步返回请求响应 Response;
- Retrofit 对返回的数据使用创建 Retrofit 实例时设置的数据转换器工厂 GsonConverterFactory 所构建的 GsonResponseBodyConverter 解析返回的数据,最终得到一个 Response 对象;
- 通过 RxJava 的 subscribe() 方法为 Observable 订阅观察者 Observer,接收并处理网络请求的返回值;
- 通过 RxJava 提供的线程调度器,可以方便的切换线程,实现在不同的线程中执行网络请求和 UI 操作。
总结
Retrofit 本质上是一个 RESTful 的 Http 网络请求框架的封装,通过大量的设计模式封装了 OkHttp,使得网络请求更加简洁易用。
- 创建 Retrofit 实例,通过 Retrofit 内部类 Builder 构建实例对象,并配置网络请求所需的各种参数及适配器工厂等;
- 创建网络请求接口的实例,Retrofit 将 Http 请求抽象成 Java 接口,在接口里用注解描述和配置网络请求参数;
- Retrofit 采用外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法: - 动态创建网络请求接口的实例(通过 InvocationHandler 对象的 invoke() 方法统一进行拦截处理);- 创建 ServiceMethod 对象,并对 ServiceMethod 对象进行网络请求参数配置:网络请求接口方法的参数、返回值和注解等;- 创建并返回 OkHttpCall 类型的网络请求对象,然后通过适配的 RxJava2CallAdapter.adapt() 方法,返回适配后的 Observable 类型的网络请求对象 BodyObservable;
- Retrofit 使用 OkHttp 的 Request 发送网络请求,网络请求最终是通过 OkHttp 内部的 RealCall 来执行,经过其拦截器链层层调用后,再一步步返回请求响应 Response;
- Retrofit 对返回的数据使用创建 Retrofit 实例时设置的数据转换器工厂 GsonConverterFactory 所构建的 GsonResponseBodyConverter 解析返回的数据,最终得到一个 Response 对象;
- 通过 RxJava 的 subscribe() 方法为 Observable 订阅观察者 Observer,接收并处理网络请求的返回值;
- 最后,通过 RxJava 提供的线程调度器,可以方便的切换线程,实现在不同的线程中执行网络请求和 UI 操作。
参考
- square/Retrofit:github.com/square/retrofit
- square/okhttp:github.com/square/okhttp
版权归原作者 neuHenry 所有, 如有侵权,请联系我们删除。