Retrofit官方文档
A type-safe HTTP client for Android and Java
概述
- Retrofit本身并不是一个网络请求框架,而是一个网络请求框架的封装
- App应用程序通过 Retrofit请求网络,实际上是使用Retrofit 接口层封装请求参数,之后由OkHttp完成后续的请求操作
- 在服务端返回数据之后,OkHttp 将原始的结果交给Retrofit, Retrofit根据用户的需求对结果进行解析
类型安全
- 即Retrofit可以在编译期检查出错误,比如AS编码警示
- 不会在运行是出现错误
使用
- 添加Retrofit库的依赖,
- 添加网络权限创建接收服务器返回数据的类(实体Bean)
- 创建用于描述网络请求的接口
- 创建Retrofit实例
- 创建网络请求接口实例
- 发送网络请求(异步/同步)
- 处理服务器返回的数据
代码
- 1.创建一个interface作为WebService的请求集合,在里面用注解(Annotation)写入需要配置的请求方法
interface GitHubService { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String?): Call<List<Repo>> //使用http注解 @HTTP(method = "get",path = "users/{user}/repos",hasBody = false) fun httpRepos(@Path("user") user: String?): Call<List<Repo>> } - 2.在正式代码里用 Retrofit 创建出 interface 的实例
- 3.调用创建出的Service实例的对应方法,创建出相应的可以用来发起网络请求的Call对象
- 4.使用 Call.execute() 或者 Call.enqueue() 来发起请求
class RetrofitActivity:AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_retrofit); //1 构建一个retrofit对象 val retrofit = Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//RXJava支持 .build() //2. 获取接口的代理对象,传入字节码 val service = retrofit.create(GitHubService::class.java) //3 获取具体的请求业务方法 val repos: Call<List<Repo>> = service.listRepos("octocat") //4 发起异步请求 repos.enqueue(object : Callback<List<Repo>?> { override fun onFailure(call: Call<List<Repo>?>, t: Throwable) { println("Response: ${t.message}") } override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) { println("Response: ${response.body()!![0].name}") } }) //同步的,不切换线程(安卓中不使用) // repos.execute() val listReposRx = service.listReposRx("octocat") listReposRx.subscribe() } }
静态代理与动态代理
代理模式: 为其他对象提供一种代理,用以控制对这个对象的访问
静态代理
//抽象类
abstract class AbstractObject {
protected abstract void operation();
}
//真实对象
class RealObject extends AbstractObject {
@Override
protected void operation() {
System.out.println("Do something");
}
}
//代理对象
class ProxyObject extends AbstractObject {
//对目标类的引用
RealObject realObject;
public ProxyObject(RealObject realObject) {
this.realObject = realObject;
}
//可以在真实目标对象操作前后加需要的逻辑
@Override
protected void operation() {
System.out.println("do something before real operation");
if (realObject == null){
realObject = new RealObject();
}
realObject.operation();
System.out.println("do something before after operation");
}
}
动态代理
动态代理:代理类在程序运行时创建的代理方式,根据在代码中的配置动态生成。相比于静态代理,动态代理能够很方便地对代理类的函数做统一的处理,而不用频繁修改每一个代理类的函数。
- 无侵入
- 方法增强
分类
- jdk动态代理:不同于静态代理,jdk动态代理只能为接口创建代理对象
- CGLIB
jdk动态代理举例
InvocationHandler
- 每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接口的实现
- invoke方法的参数中可以获取参数
- invoke方法的返回值被返回给使用者
步骤
- 创建接口
- 创建真实对象
- 创建代理类
- 客户端使用
- 通过java.lang.reflect.Proxy.newProxyInstance(...)方法获取真实对象的代理对象
- 通过代理对象调用真实对象相关接口实现的方法,这个时候就会跳转到这个代理对象所关联的handler的invoke()方法
//1. 创建接口
interface Subject {
void shoping();
}
//2. 创建真实对象
class Man implements Subject{
@Override public void shoping() {
System.out.println("DSH 要去买东西");
}
}
//3.创建代理类
class Proxy implements InvocationHandler {
private Object target;//要代理的真实对象
public Proxy(Object target) {
this.target = target;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy: "+proxy.getClass().getName());
System.out.println("before...");
method.invoke(target,args);
System.out.println("after");
return null;
}
}
//4. 客户端调用
class Client {
public static void main(String[] args) {
Subject man = new Man();
Proxy p = new Proxy(man);
//通过java.lang.reflect.Proxy.newProxyInstance(...)方法获取真实对象的代理对象
Subject subject = (Subject) java.lang.reflect.Proxy.
newProxyInstance(man.getClass().getClassLoader(),
man.getClass().getInterfaces(),
p);
//通过代理对象调用真实对象相关接口实现的方法,
// 这个时候就会跳转到这个代理对象所关联的handler的invoke()方法
subject.shoping();
//获得真实对象的代理对象所对应的Class对象的名称,用字符串表示
System.out.println(subject.getClass().getName());
//输出结果
//proxy: com.dsh.imocc.proxy.dynamic.$Proxy0
//before...
//DSH 要去买东西
//after
//com.dsh.imocc.proxy.dynamic.$Proxy0
}
}
框架构成
网络请求的八个步骤及七个关键的成员变量
八个步骤
- 创建retrofit实例
- 定义一个网络请求接口并为接口中的方法添加注解
- 通过动态代理生成网络请求对象
- 通过网络请求适配器将网络请求对象进行平台适配
- 通过网络请求执行器发送网络请求
- 通过数据转换器解析数据
- 通过回调执行器切换线程
- 用户在主线程处理返回结果
七个关键成员变量
public final class Retrofit {
...
//1. 缓存
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
//2. 请求工厂 默认是OkhttpClient
final okhttp3.Call.Factory callFactory;
//3. 基地址
final HttpUrl baseUrl;
//4. 数据转换器工厂集合
final List<Converter.Factory> converterFactories;
//5. 网络请求适配器工厂集合
final List<CallAdapter.Factory> callAdapterFactories;
//6. 线程回调 在安卓中默认是主线程
final @Nullable Executor callbackExecutor;
//7. 标志位 是否立即解析接口中的方法
final boolean validateEagerly;
...
}
- retrofit网络请求默认返回Call,添加ConvertFactory之后可以支持自定义实体Call,添加CallAdapterFactory之后支持自定义返回类型Observable,这也是我们开发中常见的方式
retroft中builder构建者模式&builder内部类解析
构造器中通过Platform.get()创建了默认的转换器、适配器、线程调度器等
val retrofit = Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//RXJava支持
.build()
- baseUrl:将String类型的url转换为HttpUrl对象
- addConverterFactory:设置数据解析器,GsonConverterFactory.create()就是一个Gson的赋值操作
- addCallAdapterFactory:数据适配器工厂,原理同上
build()方法
源码分析
1.Retrofit.create方法
- 通过 Retrofit.create(Class) 方法创建出 Service interface 的实例,从 而使得 Service 中配置的方法变得可用,这是 Retrofit 代码结构的核心;
retrofit.create(GitHubService::class.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];
@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.
//如果是Object类自有的方法就直接执行
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是平台中自有的方法也直接执行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//call就做了两件事
//一:生成一个真正的OKHTTP的call并且加入请求队列
//二:对返回结果利用之前定义的converter转换后返回给callback
//之所以会用adapter的adapt方法主要是为了线程切换(rxjava的转换),这里是把结果切回主线程
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
1.1 验证服务的接口:validateServiceInterface()
验证是否为接口而且是不继承其他接口的接口
1.2 Proxy.newProxyInstance():动态代理创建 Service接口 实例。
- Retrofit.create() 方法内部,使用的是Proxy.newProxyInstance() 方法来创建 Service 实例。
- 这个方法会为参 数中的多个 interface (具体到 Retrofit 来说,是固定传入一个 interface)创建 一个对象,这个对象实现了所有 interface 的每个方法,并且每个方法的实现都 是雷同的:调用对象实例内部的一个 InvocationHandler 成员变量的invoke() 方法,并把自己的方法信息传递进去。
- 这样就在实质上实现了代理 逻辑:interface 中的方法全部由一个另外设定的 InvocationHandler 对象 来进行代理操作。并且,这些方法的具体实现是在运行时生成 interface 实例时 才确定的,而不是在编译时(虽然在编译时就已经可以通过代码逻辑推断出 来)。这就是网上所说的「动态代理机制」的具体含义。
通过动态代理实际生成了类似如下的实际运行代码
class ProxyGithubService implements GitHubService{
InvocationHandler invocationHandler = 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 (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
};
@NotNull @Override
public Call<List<Repo>> listRepos(@org.jetbrains.annotations.Nullable String user) {
Method method = null;
try {
method = GitHubService.class.getDeclaredMethod("listRepos",String.class);
return (Call<List<Repo>>) invocationHandler.invoke(this,method, new String[] { user });
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
因此, invoke() 方法中的逻辑,就是 Retrofit 创建 Service 实例的关键。
2.invoke核心方法loadServiceMethod()
因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法 loadServiceMethod(method);
2.1 ServiceMethod 的创建:
- 核心是ServiceMethod.parseAnnotations
- 这行代码负责读取 interface 中原方法的信息(包括返回值类型、方法注解、参 数类型、参数注解),并将这些信息做初步分析。实际返回的是一个CallAdapted 。
- 首先从之前加载过的缓存中取,
- 没加载过就重新构建并加入到缓存中
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;
}
追踪代码,到达ServiceMethod,分步解析 如下2.2 2.3
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
2.2 解析注解->RequestFactory.parseAnnotations->RequestFactory生成
在retrofit.create()中loadServiceMethod的时候,RequestFactory通过Builder构造一个RequestFactory对象并返回,之后用于网络请求
- build过程包含parseMethodAnnotation(annotation)、parseParameter、parseHeader等,最后生成请求和返回所需要的全部参数
2.3 CallAdapted对象生成->HttpServiceMethod.parseAnnotations
- ServiceMethod.parseAnnotations(this, method) -> HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
- 这里实际上构造了一个CallAdapted对象
... if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } ...
2.4 OkHttpCall 的创建:
loadServiceMethod(method)返回了一个CallAdapted对象之后,就开始执行invoke()这个方法
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
继续追踪源码,于是到了HttpServiceMethod中来
- OkHttpCall 是 retrofit2.Call 的子类。
- 这行代码负责将 ServiceMethod 解读到的信息(主要是一个 RequestFactory 、一个OkHttpClient 和一个 ResponseConverter )封装进 OkHttpCall ;
- 而这个对象可以在需要的时候(例如它的 enqueue() 方法被调用的时候), 利用 RequestFactory 和 OkHttpClient 来创建一个 okhttp3.Call 对象,并调用这个 okhttp3.Call 对象来进行网络请求的发起,比如异步的enquue。
- 然后利用ResponseConverter 对结果进行预处理之后,交回给 Retrofit 的 Callback 。
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
...
}
2.5 OkHttpCall的enqueue()方法
-
下面代码中最重要的则是createRawCall(),也就是创建OKHTTP的call,然后利用这个call调用OKHTTP的enqueque来进行真正的网络请求,同时将返回值返回到callback中。
@Override public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { //1. createRawCall 创建okhttp的call call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //2. 解析response response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } }); } -
到这里已经可以拿到网络通信结果了当然是通过 parseResponse(rawResponse) 转换的最终结果,而这个转换则是通过初始化时 addConverterFactory 添加的转换器
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); ... ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { ... } } -
responseConverter来源
- 追踪源码,responseConverter来自于HttpServiceMethod中CallAdapted创建之前
2.6 adapt() 方法:
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);中拿到了okhttp请求结果之后,接下来继续执行adapt(call, args)方法
- 这个方法会使用一个 CallAdapter 对象来把 OkHttpCall 对象进行转换,生成一个新 的对象。默认情况下,返回的是一个 ExecutorCallbackCall ,它的作用是把操 作切回主线程后再交给 Callback 。
- 另外,如果有自定义的 CallAdapter,这里也可以生成别的类型的对象,例如 RxJava 的 Observable ,来让 Retrofit 可以和 RxJava 结合使用。
callAdapter是哪里来的呢?
- 在retrofit进行build()的时候会创建一个默认的callAdapter,放在callAdapterFactories容器中
- 用户自定义的callAdapter需要在retrofit对象构建时传入
最后流程总结如下
我的总结
一句话总结:
Retrofit通过动态代理为接口创建了实例进行了okhttp网络请求.
其内部通过拦截接口参数、注解解析等方式获取到了http网络请求所需的各种信息,okhttp请求结果通过数据转换和线程调度返回给调用者。
小结
- Retrofit 通过动态代理为接口创建了实例进行okhttp网络请求
- Retrofit 核心方法是loadServiceMethod(method).invoke(args)
- loadServiceMethod(method).invoke(args) 这其中又包含了loadServiceMethod(method)和invoke(args)两个部分
loadServiceMethod(method)
- loadServiceMethod(method)方法调用了ServiceMethod.parseAnnotations(...)并返回一个RequestFactory对象
- 这个方法中首先调用了RequestFactory.parseAnnotations(retrofit, method)方法,这个方法实际上通过RequestFactory的build方法构建了一个RequestFactory对象,这个对象中包含了http请求所需的信息,具体是通过解析注解信息(包括返回值类型、方法注解、参 数类型、参数注解)
然后通过返回的RequestFactory对象构造了一个CallAdapted对象
//参数1,包含请求信息的requestFactory
//参数2,实际上就是OkHttpClient
//参数3,数据转换器
//参数4,包装了Android默认MainThreadExecutor的DefaultCallAdapterFactory对象 或RxJava2CallAdapterFactory等
CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
invoke(args)
invoke方法创建了OkHttpCall对象,在里边是通过okhttp进行网络请求
- adapt方法:这个方法会使用一个 CallAdapter 对象来把 OkHttpCall 对象进行转换,生成一个新 的对象。默认情况下,返回的是一个 ExecutorCallbackCall ,它的作用是把操 作切回主线程后再交给 Callback 。
- 另外,如果有自定义的 CallAdapter,这里也可以生成别的类型的对象,例如 RxJava 的 Observable ,来让 Retrofit 可以和 RxJava 结合使用。
Retrofit中的注解
请求方法类
参数类
标记类
Retrofit中的设计模式
1.建造者模式
Retrofit对象的创建、ServiceMethod对象创建都使用Build模式,将复杂对象的创建和表示分离,调用者不需要知道复杂的创建过程,使用Build的相关方法进行配置创建对象。
如Retrofit.builder等
2.外观模式
Retrofit对外提供了统一的调度,屏蔽了内部的实现,使得使用该网络库简单便捷。
门面模式:提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使用子系统更容易使用
3.代理模式
Retrofit核心代码Proxy.newProxyInstance() 动态代理
好处:通过代理帮我们进行具体的接口实现,而不需要我们写具体的接口实现
4. 其他:适配器模式、工厂模式、策略模式、单例模式
适配器模式、工厂模式
retrofit2.CallAdapter类
适配器模式
public interface CallAdapter<R, T> {
...
T adapt(Call<R> call);
...
}
工厂模式: 返回不同的adapter
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
策略模式
retrofit2.Converter类就使用了策略模式
单例模式(饿汉式)
retrofit2.Platform类
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
...
}
Retrofit面试题解
- retrofit线程切换问题
- MainThreadExecutor中的
Handler handler = new Handler(Looper.getMainLooper());实际上就是通过handler调度
- MainThreadExecutor中的
- rxjava和retrofit如何结合进行网络请求
- 通过
addCallAdapterFactory(RxJavaCallAdapterFactory.create())添加rxjava适配器 - 网络请求接口创建的是Observable对象
- 通过rxjava操作符进行线程调度
- 通过
- Hook与动态代理
- Hook:通过某种手段对一件事物进行改头换面,从而劫持Hook的目标来以达到控制目标的行为的目的。