Retrofit源码分析:动态代理获取Api接口实例,解析注解生成request,线程切换

server/2024/12/24 7:30:09/

目录

一,Retrofit的基本使用

1.定义api接口

2.创建Retrofit实例

3.获取api接口实例发起请求

二,静态代理和动态代理

1,静态代理

2,动态代理

三,动态代理获取Api接口实例

四,解析接口方法注解,生成请求方法

五,代理发起网络请求

六,Retrofit如何实现线程切换?


一,Retrofit的基本使用

1.定义api接口

java">public interface ApiService {// GET 请求示例@GET("users/{id}")Call<User> getUser(@Path("id") int userId);// POST 请求示例@POST("users")Call<User> createUser(@Body User user);// 带查询参数的 GET 请求示例@GET("users")Call<List<User>> getUsers(@Query("page") int page, @Query("size") int size);
}

2.创建Retrofit实例

java">public class ApiClient {private static final String BASE_URL = "https://api.github.com/";private static Retrofit retrofit;public static Retrofit getClient() {if (retrofit == null) {retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())  // 使用 Gson 解析器.build();}return retrofit;}
}

3.获取api接口实例发起请求

java">import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 apiService 实例ApiService apiService = ApiClient.getClient().create(ApiService.class);// 创建请求Call<User> call = apiService.getUser("octocat");// 异步请求call.enqueue(new Callback<User>() {@Overridepublic void onResponse(Call<User> call, Response<User> response) {if (response.isSuccessful()) {// 请求成功,处理数据User user = response.body();Log.d("Retrofit", "User: " + user.getName());} else {// 请求失败Log.e("Retrofit", "Request failed");}}@Overridepublic void onFailure(Call<User> call, Throwable t) {// 请求失败Log.e("Retrofit", "Request error", t);}});}
}

 

从Retrofit的使用入手,Retrofit的核心在于:

  • 通过动态代理获取apiService实例,对api请求方法进行拓展。
  • 在代理对象的invoke方法中对接口方法进行解析,解析注解,参数,参数注解,返回类型等。
  • 代理用于发送请求的Call对象执行网络请求,并拦截响应。
  • 底层使用Handler机制切换到主线程,并将响应结果返回。

二,静态代理和动态代理

首先,我们先了解一下代理模式

代理模式:通过代理对象来代替真实对象的访问,从而在不修改原对象的情况下,对原对象的方法进行拓展

 

代理模式一般包含这几个元素:

  • 委托类(被代理的类)
  • 接口(委托类实现的方法)
  • 代理类

1,静态代理

静态代理分为以下几个步骤:

  1. 创建一个接口,定义方法
  2. 创建一个委托类实现接口
  3. 创建一个代理类,持有委托类的引用,实现与委托类相同的接口

(1)创建接口

/*
委托接口*/
interface ClientInterface {fun call()
}

(2)创建委托类实现接口

/*
委托类*/
class Client : ClientInterface {override fun call() {println("Client Call")}
}

(3)创建代理类,实现与委托类相同的接口

/*
代理类*/
class Proxy : ClientInterface {var client : Client? = nullfun setInstance(client: Client){this.client = client;}override fun call() {println("proxy pre call")client?.call()println("proxy aft call")}
}

这样我们就可以通过使用代理类的call方法,从而对委托类的方法进行拓展;

2,动态代理

动态代理与静态代理的区别就是:动态代理的代理对象由Java中的Proxy.newProxyInstance()在运行时动态生成。

java">@CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException

这个方法需要的三个参数为:

  •  loader:委托类的类加载器
  • interfaces:委托类实现的接口
  • h:一个实现了InvocationHandler的类,在这个类的invoke方法中对委托类的方法进行拓展

(1)同样创建委托类和接口

/*
委托类,也就是代理对象
*/
class Client : ClientInterface {override fun call() {println("client call")}
}/*
委托接口,代理类实现的接口*/
interface ClientInterface {fun call()fun call1()
}

(2)创建实现InvocationHandler的类

/*
实现了InvocationHandler的类*/
class CallInvocationHandler(private var target: Any) : InvocationHandler {//代理类调用的方法会被转发到这里运行override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? {println("before client: ${args.toString()} call: ${method.name}")return method.invoke(target, args)}
}

(3)使用Proxy.newProxyInstance()生成代理对象

class Application3 {fun main(){val client : ClientInterface = Client()val proxy = Proxy.newProxyInstance(client::class.java.classLoader, //代理对象的类加载器,用于加载代理对象arrayOf(client::class.java), //代理对象实现的接口,也就是代理对象要进行的业务CallInvocationHandler(client) //实现了 InvocationHandler 接口的对象,通过代理类调用代理对象的方法时,就会转发到invoke方法中被调用) as Clientproxy.call();}
}

动态代理(JDK动态代理)只能代理实现了接口的类,所以与其说代理类代理了委托类,不如说它是代理了接口 

三,动态代理获取Api接口实例

当我们明白了动态代理之后,我们再来看Retrofit的create方法:

java">private val apiService : ApiService = RetrofitClient.getInstance().create(ApiService::class.java)public <T> T create(final Class<T> service) {validateServiceInterface(service);//动态代理,获取ApiService的代理对象return (T)Proxy.newProxyInstance(service.getClassLoader(),new Class<?>[] {service},new InvocationHandler() {private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];@Overridepublic @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {// object类中的方法直接调用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}args = args != null ? args : emptyArgs;//检查是否含有默认实现,如果有直接按默认实现调用,//没有则进入loadServiceMethod方法return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}});
}//在这里对接口中的方法进行解析
ServiceMethod<?> loadServiceMethod(Method method) {//请求方法缓存,避免重复加载ServiceMethod<?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {//没有缓存,解析方法result = ServiceMethod.parseAnnotations(this, method);serviceMethodCache.put(method, result);}}return result;
}

可见Retrofit通过create方法创建了一个ApiService的代理类。通过ApiService代理类调用请求方法时,就会被转发到InvocationHandler的invoke方法中进行解析(loadServiceMethod)和调用(invoke)。

四,解析接口方法注解,生成请求方法

接着,Retrofit通过ServiceMethod类对方法及方法注解进行解析:

java">abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//构建请求工厂RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);...//封装,形成完整的可执行的请求return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}abstract @Nullable T invoke(Object[] args);
}

ServiceMethod是一个抽象类,实现类为HttpServiceMethod。

ServiceMethod首先构建了一个RequestFactory,RequestFactory中封装了从接口方法解析到的信息,包括:

  • 请求方法(GET, POST等)
  • baseUrl和请求的相对路径
  • 请求头,请求参数,请求体等
java">
final class RequestFactory {static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {return new Builder(retrofit, method).build();}private final Method method; //接口方法private final HttpUrl baseUrl; //baseUrlfinal String httpMethod; //请求方法 get,post等private final @Nullable String relativeUrl; //请求的相对路径private final @Nullable Headers headers; //请求头private final @Nullable MediaType contentType; //请求体MIME类型private final boolean hasBody; //是否包含请求体private final boolean isFormEncoded; //是否是表单编码请求private final boolean isMultipart; //是否是多部分请求private final ParameterHandler<?>[] parameterHandlers; //参数处理数组,根据参数注解决定如何处理参数final boolean isKotlinSuspendFunction; //是否为kotlin挂起函数}

接着在HttpServiceMethod中,使用适配器,格式转换器,结合RequestFactory将请求信息封装为可执行的完整的请求

核心代码:

java">static <T> HttpServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method);Type responseType = callAdapter.responseType();Converter<ResponseBody, T> responseConverter = createResponseConverter(retrofit, method, responseType);return new HttpServiceMethod<>(requestFactory, callAdapter, responseConverter);
}

核心组件:

  • callAdapter适配器:将底层的call对象适配为用户接口返回的类型(Call<T>, Flow<T>, LiveData<T>等);

  • converter格式转化器:例如转化Json格式数据

  • RequestFactory:之前封装好的请求信息

五,代理发起网络请求

在请求构建完毕后,就会调用invoke方法,具体调用的是HttpServiceMethod类中的invoke方法

invoke方法中又返回了adapt方法的调用,adapt方法的具体实现交给三个子类:

  • CallAdapted<ResponseT, ReturnT>:适配返回类型为标准Java类型,如Call<T>,或者RxJava的Single<T>, Observer<T>类型。

  • SuspendForResponse<ResponseT>:适配 Kotlin 协程场景,当接口方法的返回类型为 suspend fun 且需要返回一个 Respond<T>(完整的 HTTP 响应对象)时使用。

  • SuspendForBody<ResponseT>:适配 Kotlin 协程场景,当接口方法的返回类型为 suspend fun 且只需要返回响应体对象 T(不需要完整的 HTTP 响应对象)时使用。

java">  @Overridefinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {}static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {}static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {}

一般情况,使用的都是CallAdapted子类,CallAdapted子类中的adapt方法返回callAdapter的adapt方法调用:

java">static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {private final CallAdapter<ResponseT, ReturnT> callAdapter;CallAdapted(RequestFactory requestFactory,okhttp3.Call.Factory callFactory,Converter<ResponseBody, ResponseT> responseConverter,CallAdapter<ResponseT, ReturnT> callAdapter) {super(requestFactory, callFactory, responseConverter);this.callAdapter = callAdapter;}@Overrideprotected ReturnT adapt(Call<ResponseT> call, Object[] args) {return callAdapter.adapt(call);}}

返回类型为Call<T>,对应的callAdapter由Retrofit默认添加的DefaultCallAdapterFactory生成:

java">@Overridepublic @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<Foo> or Call<? extends Foo>");}final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);final Executor executor =Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)? null: callbackExecutor;return new CallAdapter<Object, Call<?>>() {@Overridepublic Type responseType() {return responseType;}@Overridepublic Call<Object> adapt(Call<Object> call) {//这里使用代理模式,将okHttpCall的功能代理到ExecutorCallbackCall中return executor == null ? call : new ExecutorCallbackCall<>(executor, call);}};}

adapt方法最后返回ExecutorCallbackCall对象,所以调用ApiService代理类的请求方法,最终返回的是call对象为ExecutorCallbackCall对象。

或者说是使用了代理模式,将call的功能代理到了ExecutorCallbackCall中,当我们调用call的异步方法enquque时,最终调用到的是ExecutorCallbackCall的enquque方法。

在ExecutorCallbackCall的enquque方法调用了原call对象的异步请求方法,并拦截了onResponse 和 onFailure 回调,切换到指定的线程(通常是主线程),也就是Retrofit中的onResponse 和 onFailure 回调最终是在主线程中获取到的。

至此,Retrofit的整个流程就结束了。

java">static final class ExecutorCallbackCall<T> implements Call<T> {final Executor callbackExecutor;final Call<T> delegate; //被代理的call对象ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {this.callbackExecutor = callbackExecutor;this.delegate = delegate;}@Overridepublic void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");//调用原call对象的异步请求方法delegate.enqueue(new Callback<T>() {//拦截底层的 onResponse 和 onFailure 回调,切换到指定的线程(通常是主线程)。@Overridepublic void onResponse(Call<T> call, final Response<T> response) {//这里切换到主线程callbackExecutor.execute(() -> {if (delegate.isCanceled()) {callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}});}@Overridepublic void onFailure(Call<T> call, final Throwable t) {callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));}});}@Overridepublic boolean isExecuted() {return delegate.isExecuted();}@Overridepublic Response<T> execute() throws IOException {return delegate.execute();}@Overridepublic void cancel() {delegate.cancel();}@Overridepublic boolean isCanceled() {return delegate.isCanceled();}@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.@Overridepublic Call<T> clone() {return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());}@Overridepublic Request request() {return delegate.request();}@Overridepublic Timeout timeout() {return delegate.timeout();}}

六,Retrofit如何实现线程切换?

ExecutorCallbackCall代理类发起请求后,在响应回调中,通过callbackExecutor.execute切换到主线程。

这里的callbackExecutor是Retrofit在构建时配置的:

java">public Retrofit build() {Executor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {callbackExecutor = platform.defaultCallbackExecutor();}}

在Retrofit的Platform中,Android平台默认返回一个MainThreadExecutor,在MainThreadExecutor的execute方法中,线程通过Hanlder进行切换。

java">static class Android extends Platform {@Overridepublic Executor defaultCallbackExecutor() {return new MainThreadExecutor();}static class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());@Overridepublic void execute(Runnable r) {//通过Handler进行线程切换handler.post(r);}}
}

http://www.ppmy.cn/server/152705.html

相关文章

解锁 GitBook 的奥秘:从入门到精通之旅

一、GitBook 初印象 在当今数字化时代&#xff0c;知识的传播与分享变得愈发便捷和多样化。GitBook 作为一款强大的文档编辑与电子书制作工具&#xff0c;正逐渐崭露头角&#xff0c;为广大创作者、开发者和知识爱好者提供了一个高效且灵活的平台。它不仅仅是一个简单的文档编写…

拓展AI超级智能后的人类生活场景

一、日常生活领域 &#xff08;一&#xff09;家居生活 在AI超级智能拓展之后&#xff0c;家居生活将发生翻天覆地的变化。清晨&#xff0c;当第一缕阳光透过智能窗帘的缝隙照进房间时&#xff0c;智能管家已经根据主人的生物钟和当天的日程安排&#xff0c;轻柔地播放起舒缓的…

重温设计模式--单例模式

文章目录 单例模式&#xff08;Singleton Pattern&#xff09;概述单例模式的实现方式及代码示例1. 饿汉式单例&#xff08;在程序启动时就创建实例&#xff09;2. 懒汉式单例&#xff08;在第一次使用时才创建实例&#xff09; 单例模式的注意事项应用场景 C代码懒汉模式-经典…

图像处理基础 | 格式转换.rgb转.jpg 灰度图 python

一般情况下 .rgb 格式的存储顺序&#xff1a; 颜色顺序&#xff1a; 一般情况下&#xff0c;.rgb 文件存储的是原始的 RGB 数据&#xff08;而不是 BGR 数据&#xff09;。即每个像素是由 R&#xff08;红色&#xff09;、G&#xff08;绿色&#xff09;、B&#xff08;蓝色&…

SQL server学习10-数据库编程(中)

目录 一&#xff0c;分支语句 IF...ELSE 二&#xff0c;多路分支函数 CASE 1&#xff0c;简单CASE函数 2&#xff0c;CASE搜索函数 三&#xff0c;循环语句 WHILE 四&#xff0c;检测语句 IF...EXISTS T-SQL语言中提供了丰富的流程控制语句或函数&#xff0c;主要包含 分…

在Linux上将 `.sh` 脚本、`.jar` 包或其他脚本文件添加到开机自启动

在Linux上将 .sh 脚本、.jar 包或其他脚本文件添加到开机自启动 在Linux环境中&#xff0c;有时需要将一些程序、脚本或应用程序设置为开机时自动启动。这对于那些需要在系统启动时启动的服务或应用非常有用。本文将介绍如何将 .sh 脚本、.jar 包或其他脚本文件添加到Linux系统…

单元测试mock框架Mockito

为了继续改进 Mockito 并进一步改善单元测试体验&#xff0c;我们希望您升级到 2.1.0&#xff01;Mockito 遵循语义版本控制&#xff0c;仅在主要版本升级时包含重大更改。在库的生命周期中&#xff0c;重大更改是推出一组全新功能所必需的&#xff0c;这些功能会改变现有行为甚…

数据结构图

文章目录 图 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;数据结构专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年12月23日19点21分 图 任何一条边两头肯定都必须连接某个顶点 线性表可以是空表&#xff0c;树可以是空树&#xff0c;但…