Retrofit源码解析
图解分析
前言
在解析源码之前我们先来,整体了解一下Retrofit。Retrofit它是Square开源的一款优秀的网络框架,这个框架对okhttp进行了封装,让我们使用okhttp做网路请求更加简单。
1.使用了注解表明请求方式,和参数类型,这是retrofit的特性,也正是简化了我们的网络请求过程的地
2.retrofit的实例化采用链式调用的设计,把需要的参数传进去即可
3.调用retrofit的create
方法就可以把我们定义的接口转化成实现类,我们可以直接调用我们定义的方法进行网络请求,但是我们只定义了一个接口方法,也没有方法体,请求方式和参数类型都是注解
4.retrofit的一次网络请求示例已经结束,基于对okhttp的封装,让网络请求已经简化了很多。当然retrofit最适合的还是REST API类型的接口,方便简洁。
下面我们来看封装完整的Reftrofit请求 Rx+Retrofit+Okhttp
params.clear();
params.put("nickname", binding.etUserName.getText().toString().trim());
params.put("password", binding.etPassword.getText().toString().trim());
RetrofitManager.getInstance().create(CommonService.class)
.login(params)
.throttleFirst(1, TimeUnit.SECONDS)
.retryWhen(new RetryWhenNetworkException(2, 500, 500))
.compose(RxSchedulers.io_main())
.subscribe(new BaseObserver<UserBean>() {
@Override
protected void onFinally() {
super.onFinally();
hideLoadingDialog();
}
@Override
protected void onHandleSuccess(UserBean userBean, String desc, String content) {
SPUtil.put(getApplicationContext(), Constant.IS_LOGIN, true);
SPUtil.setObject(App.getInstance(), Constant.USER, userBean);
startActivity(new Intent(LoginActivity.this, AppIndexActivity.class));
ToastUtils.success("登录成功");
ActivityManager.getInstance().finishActivity();
}
});
/**
* 登录
*/
@POST("user/login")
@FormUrlEncoded
Observable<BaseEntity<UserBean>> login(@FieldMap Map<String, Object> params);
这是封装好的请求框架 只需要在onHandleSuccess 方法中对对应的接受参数做对应呃的操作,以及UI刷新即可
一.整体分析
先贴一段简单的例子
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.shiqiblog.com")
.build();
Call<ResponseBody> call = retrofit.create(CommonService.class).ceshi(params);
//同步
call.execute();
//异步
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
/**
* 登录
*/
@POST("userwms/login")
@FormUrlEncoded
Call<ResponseBody> ceshi(@FieldMap Map<String, Object> params);
1.初始化
Retrofit.Builder(); //从build 方法可以看出 Reftrofit使用了建造者模式。 Builder() 方法中调用了Platform.get() 方法。这个方法这里通过反射来判断,Clss.forName(String),如果有这个类名,说明就是在这个平台。因为Android也是使用的Java,所以先判断是不是在Android,再判断是不是Java。如果都不是就返回默认Platform对象
public Builder() {
this(Platform.get());
}
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
//判断当前的系统 是否为Android
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
//判断当前的系统 是否为Java
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
下面我们再来看BaseUrl方法 HttpUrl.parse(baseUrl)方法主要判断当前的 url 是否是一个合法的Http 或者https url连接 最终调用了baseUrl 参数网址转换成了一个HttpUrl对象 这个方法主要判断 网址是否以 "/"结尾
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
//返回空抛出异常
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
//盘点当前的URL 是否符合http https要求。不符合 返回null
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
// return baseUrl(httpUrl)方法 主要判断 BaseUrl是否以 / 结尾
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
client()
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
指定网络请求执行器工厂,我们发现网络请求执行器工厂是OkHttpClient,所以网络请求执行器也就是call
build()
最后最后就到了通过Builder创建Retrofit对象的时候了。
最后就到了通过Builder创建Retrofit对象的时候了。1.创建okhttp 2.指定回调工厂3.网络请求工厂4.数据转换工厂
public Retrofit build() {
//判断baseurl是否为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//okhttp是否为空 默认为 OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
/*
设置回调执行器,如果未指定,Platfrom.defaultCallbackExecutor
这里的platform在new Builder()时已经设置好,是Android,
所以回调执行器就是MainThreadExecutor,主线程
*/
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//网络请求适配器
//首先加入build()之前用户指定的callAdapterFactory
//然后再加入platfrom默认的,这里是Android,对于API>=24,
//会返回CompletableFutureCallAdapterFactory,否则返回ExecutorCallAdapterFactory
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//数据转换适配工厂
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
//返回对应实例
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
二.使用Retrofit
1.创建对应请求接口 create (接口)
public interface RequestApi{
@GET("user/login")
Call<User> getCall();
}
RequestApi request = retrofit.create(RequestApi.class);
2.开始_创建retrofit.create(接口);当我们创建的这个接口的时候。 主要做了两件事情 1).验证当前传入的接口。validateServiceInterface 遍历接口 缓存 2).创建默认 ServiceMethod 方法中 CallAdapter<T, R> callAdapter 3).创建接口代理对象 返回代理对象的真实对象
Retrofit 通过invoke为我们构造了一个 OkHttpCall ,实际上每一个 OkHttpCall 都对应于一个请求,它主要完成最基础的网络请求,而我们在接口的返回中看到的 Call 默认情况下就是 OkHttpCall 了,如果我们添加了自定义的 callAdapter,那么它就会将 OkHttp 适配成我们需要的返回值,并返回给我们。
@SuppressWarnings("unchecked")
public <T> T create(final Class<T> service) {
//验证是否为接口 长度>0
Utils.validateServiceInterface(service);
if (validateEagerly) {
//首先获取当前的Android平台,然后遍历当前接口的所有方法方法,再加载
eagerlyValidateMethods(service);
}
//返回接口代理对象 参数
1.一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
2.一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口
3.一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对 象上,并最终由其调用。
不多做解释文末 有随风 大兄弟的文章链接
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//是否为 普通对象方法 是 直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//判断这个方法是不是DefaultMethod,Java 8新属性,表示接口的方法体。
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//loadServiceMethod 请求参数 接口 参数 注解
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//返回我们需要的AdapterServiceMethod OkHttpCall 两者进行绑定
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
//loadServiceMethod加载缓存ServiceMethod,或者构建新的ServiceMethod并加入缓存serviceMethodCache
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
//非接口主体方法
if (!platform.isDefaultMethod(method)) {
//参数赋值
loadServiceMethod(method);
}
}
}
//参数赋值
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//链式调用
result = new ServiceMethod.Builder<>(this, method).build();
//赋值给定义好的Map
serviceMethodCache.put(method, result);
}
}
return result;
}
//Builder 链式
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
.........................省略部分
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
ServiceMethod —— build 方法
主要创建adapter ,获取response 参数 ,创建response转换器 , 遍历处理 方法注解
public ServiceMethod build() {
//创建Adapter
callAdapter = createCallAdapter();
// response 对象
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// 创建responseBodyConverter 方法
responseConverter = createResponseConverter();
//遍历方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//省略部分 判断为空 抛出异常的方法
//上面遍历完 注解 下面根据注解 长度 遍历 做处理
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
//省略部分代码 判断合法性代码
}
return new ServiceMethod<>(this);
}
// 处理添加注解 不做深究
1.parseHttpMethodAndPath()
2.parseHttpMethodAndPath()
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
/***
* 省略部分代码
*/
else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
return serviceMethod.callAdapter.adapt(okHttpCall);
获取到对应的Adapter 在由Okhttp发起网络请求
总结:
- Retrofit通过动态代理,用MethodHandler完成接口方法。
- Retrofit的MethodHandler通过RequestFactoryParser.parse解析,获得接口方法的参数和注解的值,传入到OkHttpCall,OkHttpCall生成okhttp3.Call完成Http请求并使用Converter解析数据回调。
- Retrofit通过工厂设置CallAdapter和Converter,CallAdapter包装转换Call,Converter转换(解析)服务器返回的数据、接口方法的注解参数。
Retrofit使用动态代理模式实现我们定义的网络请求接口,在重写invoke方法的时候构建了一个ServiceMethod对象,在构建这个对象的过程中进行了方法的注解解析得到网络请求方式httpMethod,以及参数的注解分析,拼接成一个省略baseurl的参数
动态代理参考随风大兄弟: https://blog.csdn.net/yaomingyang/article/details/81040390