Retrofit流程及设计模式全解析
Posted open-Xu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit流程及设计模式全解析相关的知识,希望对你有一定的参考价值。
版权声明:本文为openXu原创文章【openXu的博客】,未经博主允许不得以任何形式转载
文章目录
- 1. 代理模式
- 2. Retrofit接口代理对象的创建
- 3. Retorfit的Call创建
- 4. CallAdapter接口适配器
- 5. Retrofit请求流程
- 6. Retrofit对协程的支持
- 7 Retrofit调用流程
- 8 Retrofit的设计模式分析
- 8.1 外观模式(Facade Pattern)
- 8.2 建造者模式(Builder Pattern)
- 8.3 动态代理模式(Proxy Pattern)
- 8.4 静态代理模式(Proxy Pattern)
- 8.5 装饰器模式(Decorator Pattern)
- 8.6 工厂模式(Factory Pattern)
- 8.7 适配器模式(Adapter Pattern)
- 8.8 策略模式(Strategy Pattern)
- 8.9 观察者模式(Observer Pattern)
- 8.10 原型模式(Prototype Pattern)
- 8.11 享元模式(Flyweight Pattern)
- 8.12 单例模式(Singleton Pattern)
本文基于Retrofit 2.9.0版本源码分析,根据Retrofit源码窥探请求流程及框架设计中使用到的设计模式
1. 代理模式
在文章开始之前先介绍一下代理模式,因为这是Retrofit的入口,其他设计模式参考文章末尾的概括
代理模式:为对象提供一种代理以控制这个对象的访问。某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
组成:
- 抽象角色:通过接口或抽象类声明真实角色实现的业务方法
- 真实角色(委托类):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
- 代理角色(代理类):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
//抽象
interface IFlyable
void fly() throws Exception;
//真实类
class Bird implements IFlyable
@Override
public void fly() throws Exception
Thread.sleep(1000);
System.out.println("鸟挥动翅膀起飞了...");
//代理类
class FlyTimeProxy implements IFlyable
private IFlyable flyable;
public FlyTimeProxy(IFlyable flyable)
this.flyable = flyable;
@Override
public void fly() throws Exception
long start = System.currentTimeMillis();
flyable.fly(); //代理类调用真实类
long end = System.currentTimeMillis();
System.out.println("方法执行时长:" + (end - start));
class Test
public static void main(String[] args) throws Exception
//通过代理类间接访问委托类
new FlyTimeProxy(new Bird()).fly();
代理模式分为静态代理和动态代理
1.1 静态代理模式
上面示例代码中,通过FlyTimeProxy
代理来控制IFlyable
的目标子类对象,为fly方法增加了时间统计。在编写代码的时候代理类方法中直接调用了委托类,这就属于静态代理。静态代理是由程序员创建或工具生成代理类,是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
缺点:
- 代理类和委托类实现了相同的接口,出现了大量的代码重复。
- 代理对象只能服务于特定的委托对象,如果需要代理其他类,则要为其他类创建代理类。
比如FlyTimeProxy
现在只能代理IFlyable
的子类对象为fly方法计算执行时间,现在我需要为IRunnable
会跑的run()
也计算时间,就只能创建一个RunTimeProxy
代理对象了。
有没有办法我只创建一个TimeProxy
就可以代理所有类,为其方法计算执行时间呢?
1.2 动态代理模式
动态代理是在实现阶段不用关心代理类,而在运行阶段才动态创建出代理对象,它是基于反射实现的。Spring的两大思想IoC(依赖注入控制反转)和AOP(面向切面编程:在不改变源码的情况下,在方法中插入自定义逻辑)中的AOP就是基于动态代理机制实现的。
JDK提供了java.lang.reflect.InvocationHandler
和java.lang.reflect.Proxy
类来实现动态代理机制,Proxy是自动生成代理类的父类,它维护了InvocationHandler的实例对象,并提供了根据委托类自动创建代理对象的方法Proxy.newProxyInstance()
。当调用代理对象(Proxy的子类对象)的方法时实际上是调用InvocationHandler.invoke()
方法,从而控制委托类的调用
//抽象
interface IFlyable
void fly() throws Exception;
//真实类
class Bird implements IFlyable
@Override
public void fly() throws Exception
Thread.sleep(1000);
System.out.println("鸟挥动翅膀起飞了...");
/**InvocationHandler:提供了代理对象调用委托对象的功能*/
class TimeHandler implements InvocationHandler
private Object target; // 目标对象
public Object createProxyInstance(Object target)
this.target=target;
/**
* Proxy:提供用于创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
* 第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
* 第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
* 第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
/**
* 当调用代理类方法时,将会执行此方法
* @param proxy 代理对象
* @param method 目标对象的方法
* @param args 方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//在调用目标类方法前后插入逻辑
long start = System.currentTimeMillis();
method.invoke(target, args); //调用真实类
long end = System.currentTimeMillis();
System.out.println("方法执行时长:" + (end - start));
return null;
class Test
public static void main(String[] args) throws Exception
//通过代理类间接访问委托类
IFlyable proxy = (IFlyable) new TimeHandler().createProxyInstance(new Bird());
proxy.fly();
1.3 动态代理的原理
动态代理的原理是为委托类自动创建代理类,并通过反射获取代理类的实例。当调用代理类对象方法时,实际上时调用了InvocationHandler.invoke()
从而实现拦截。如下自动生成的代理类简约代码:
public final class $Proxy0 extends Proxy implements IFlyable
//代理类Proxy维护了InvocationHandler实例
public $Proxy0(InvocationHandler invocationhandler)
super(invocationhandler);
public final void fly(String s, String s1)
//调用代理类的方法实际上是调用InvocationHandler.invoke()从而实现拦截
super.h.invoke(this, m3, new Object[]
s, s1
);
private static Method m3;
static
m3 = Class.forName("IFlyable").getMethod("fly", new Class[] );
2. Retrofit接口代理对象的创建
通过retrofit.create(ApiService::class.java)
获取接口的实例对象,这个对象是一个动态代理对象,当调用代理对象的方法时,会被拦截得到方法、参数,再调用loadServiceMethod()
解析接口上的注解,封装成一个HttpServiceMethod
对象并调用其invoke()
执行Okhttp请求
/**Retrofit.java*/
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];
//调用接口代理对象方法实际上是调用了InvocationHandler.invoke()
@Override
public @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;
//如果是默认方法(如java8)就执行 platform 的默认方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
/**
* ★★★调用HttpServiceMethod.invoke()为Retrofit接口返回具体的请求类型对象,比如接口中定义的Call、Observable等
* 该语句主要做了2件事:
* ①. Retrofit的Call创建
* ②. 通过接口适配器CallAdapterFactory将Call对象转换成其他对象(RxJava方式、挂起函数等)
*/
: loadServiceMethod(method).invoke(args);
);
3. Retorfit的Call创建
通过Retrofit注解定义的服务器接口方法类我们称为接口,看源码之前,我们要弄清涉及到的主要类以及他们的作用:
ServiceMethod
:这个抽象类代表一个接口方法对象,它主要提供了通过RequestFactory
解析方法上注解的功能,然后交给它的子类HttpServiceMethod
处理,并定义了invoke方法,用于返回接口方法的值RequestFactory
:这个类用于解析接口方法的注解,并提供了create(Object[] args)
方法根据注解配置创建出okhttp3.Request
对象,Request代表Okhttp的一个请求HttpServiceMethod
:它是ServiceMethod的抽象子类,它将接口方法调用适配为一个Http调用。它维护了requestFactory
,具备将接口方法转换为Request对象的能力,并且实现了invoke方法用于创建了Retrofit的Call对象,并通过接口适配器将Call转换成接口方法对应的返回类型
/**Retrofit.java*/
//接口可能被请求多次,缓存提升性能
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method)
//从缓存中获取接口方法对应的ServiceMethod对象,
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache)
result = serviceMethodCache.get(method);
if (result == null)
//1 解析接口方法上的注解,创建ServiceMethod对象
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result); //缓存
return result;
/**ServiceMethod.java*/
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method)
//2 通过RequestFactory解析接口上的注解
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
//3 获取一个HttpServiceMethod的子类对象
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
/**HttpServiceMethod将接口方法的调用适配为一个Http调用*/
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT>
//根据接口方法配置创建一个HttpServiceMethod子类对象
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
...
//接口适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
//4 返回一个HttpServiceMethod的子类对象,并将接口适配器传入构造方法
if (!isKotlinSuspendFunction)
return new CallAdapted<>(..., callAdapter);
else if (continuationWantsResponse)
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(...,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
...
@Override
final ReturnT invoke(Object[] args)
//5 ★★★创建一个Retrofit的Call对象,表示一个网络请求任务
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//6 ★★★adapt的目的是将Call转换成其他对象类型,比如RxJava的Observable
return adapt(call, args);
当调用接口代理对象方法时,实际上是调用到了loadServiceMethod(method).invoke(args)
,loadServiceMethod(method)
的作用是根据接口方法的定义创建出不同的HttpServiceMethod
子类对象,然后调用该对象的invoke()方法,invoke中创建了Call对象(OkHttpCall
的实例)。
然后通过adapt()
方法将Call对象转换成接口真正的返回类型。比如下面定义的两个接口,调用login()
时,adapt将返回Call对象,调用login1()
时它将返回一个Observable
对象,adapt()
是通过调用接口适配器对象CallAdapter.adapt(call)
来对Call对象进行转换的。
ApiService接口
|--fun login():Call<User> //Call
|--fun login1(): Observable<User> //RxJava
4. CallAdapter接口适配器
在定义Retrofit服务器接口时,可以支持返回Call、Observable等等,如下:
ApiService接口
|--fun login():Call<User> //Call
|--suspend fun login1(): User //suspend协程挂起函数,稍后单独讲
|--fun login2(): Observable<User> //RxJava
private val retrofit = Retrofit.Builder()
...
.addCallAdapterFactory(RxJava3CallAdapterFactory.create()) //添加对RxJava的支持
.build()
Retrofit可以根据接口方法返回类型自动适配返回对应的对象,这都是接口适配器的作用。接下来我们看看接口适配器有哪些?他们是怎么工作的?
4.1 CallAdapter & Factory
/**将R适配为T*/
public interface CallAdapter<R, T>
//Retrofit接口方法返回类型的泛型参数类型,比如方法返回类型<User>,此处将返回User
Type responseType();
//将R转换为T返回
T adapt(<R> );
abstract class Factory
/**根据Retrofit接口方法的返回类型创建一个适配器实例对象 */
public abstract @Nullable Adapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
...
CallAdapter
接口代表接口适配器,它有一个内部抽象工厂类Factory
。适配器工厂CallAdapter.Factory的作用是提供了get()
方法判断匹配创建适配器CallAdapter对象,而适配器提供了adapt()
将OkHttpCall
类型的call对象转换成接口方法返回值对应类型对象。
构建Retrofit时可添加很多种接口适配器工厂以适配接口方法的不同返回类型,这其中就包括平台默认的接口适配器和通过addAdapterFactory()
额外添加的,这些适配器工厂都被保存在callAdapterFactories
集合中,这就存在两个问题:
- 怎样从集合中根据接口方法匹配到合适的适配器对象?
- 适配器是怎么完成call转换的?
public final class Retrofit
//接口适配器工厂集合,构造方法中被赋值
final List<CallAdapter.Factory> callAdapterFactories;
//Retrofit建造者
public static final class Builder
private final Platform platform; //代表当前平台,比如android
Builder(Platform platform) this.platform = platform;
//添加额外的接口适配器工厂支持
public Builder addAdapterFactory(Adapter.Factory factory)
AdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
public Builder() this(Platform.get());
public Retrofit build()
...
//★★★接口适配器工厂集合,首先包含了通过addCallAdapterFactory添加的接口适配器工厂
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//★★★添加平台默认的接口适配器,platform代表平台,比如Android平台默认的接口适配器是DefaultCallAdapterFactory,如果是使用Java8则还会有CompletableFutureCallAdapterFactory(这个适配器将支持kotlin挂起函数)
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
...
//创建Retrofit对象,并将接口适配器通过构造方法传入
return new Retrofit(...,unmodifiableList(callAdapterFactories),...);
/**★★★根据接口返回类型获取与之匹配的适配器对象*/
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations)
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++)
//遍历适配器工厂集合
CallAdapter<?, ?> adapter = callAdapterFactories.get(i)
//根据接口返回类型returnType判断是否符合要求,如果不符合返回null,符合则创建一个接口适配器对象
.get(returnType, annotations, this);
if (adapter != null) //直到匹配到合适的接口适配器,并返回
return adapter;
...
...
HttpServiceMethod的invoke()方法首先创建了一个OkHttpCall
类型的call对象,然后调用adapt(call, args)
将call转换成接口返回类型。adapt()
方法实际上是通过调用HttpServiceMethod
的子类维护的callAdapter
接口适配器对象的callAdapter.adapt(call)
方法完成的。
HttpServiceMethod.parseAnnotations()
方法中通过createCallAdapter()
为接口方法创建了一个接口适配器CallAdapter对象并传给其子类对象,跟踪代码发现最后调用到Retrofit的nextCallAdapter()
方法去获取适配器对象。该方法将遍历callAdapterFactories
集合,调用CallAdapter.Factory.get()
方法来获取适配器对象,如果接口返回类型returnType和适配器正好匹配上则创建一个适配器对象,否则返回空继续遍历直到匹配到合适的接口适配器,这就回答了上述第一个问题。
关于call是怎么转换的,接下来我们通过查看几个具体的接口适配器就明白了。
4.2 平台默认的DefaultCallAdapterFactory
Retrofit默认提供对Call的支持,因为Retrofit.build()
时添加了Android
平台默认的接口适配工厂DefaultCallAdapterFactory
,该工厂会判断接口方法的返回类型是否是Call类型,如果是则创建默认接口适
以上是关于Retrofit流程及设计模式全解析的主要内容,如果未能解决你的问题,请参考以下文章