您的位置:首页 > 理论基础 > 计算机网络

Retrofit源码分析

2016-07-06 02:52 417 查看
通过一次网络请求,来分析Retrofit源码

Retrofit第三方开源库,最近在很多地方都看到有人在使用。用了之后,感觉这是一个很简洁,代码维护成本较低的开源库。

Retrofit一般会依赖OkHttp这个库,它访问网络依赖OkHttpClient,通常情况下都是:Retrofit + OkHttp一起使用的。

Retrofit也支持RxJava作为适配器工厂,Retrofit + OkHttp + RxJava 的组合也是很多开发者喜欢的。

在这里,通过Retrofit来请求一次网络,一步一步分析Retrofit内部原理与源码。

compile "com.squareup.retrofit2:retrofit:2.0.2"
compile "com.squareup.retrofit2:converter-gson:2.0.2"
compile 'com.squareup.okhttp3:okhttp:3.2.0'


简单来说,Retrofit通过:注解 + 反射 + 动态代理。面向对象的形式来处理一次网络请求。

Retrofit让请求网络的代码变得简洁起来了,维护成本也低很多。

Retrofit让开发者只关心两个问题:

1,请求网络接口类的定义。

2,解析服务器传递过来的json生成Java Bean。

下面就从使用方式上来分析Retrofit的源码。

例如,让Retrofit来完成这样的一次网络请求,将服务器传递过来的json转化成Java Bean。

Get请求:

https://api.douban.com/v2/fm/app_channels


1,首先,生成请求网络接口类。

public interface AppChannelsApi {

@GET("v2/fm/app_channels")
Call<AppChannels> getAppCannels();
}


2,分析服务器传递过来的json生成Java Bean。

public class AppChannels {

private List<GroupsBean> groups;

...


3,声明HostUrl。

public class HostUrl {

public static final String HOST = "https://api.douban.com/";
}


4,创建OkHttpClient。

public class HttpClient {

private static OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();

public static OkHttpClient get() {
return mOkHttpClient;
}
}


5,生成Retrofit对象,通过Retrofit对象获取到接口的实现类。

public class AppChannelsClient {

private static AppChannelsApi api;

public static AppChannelsApi get() {
if (api == null) {
synchronized (AppChannelsClient.class) {
if (null == api) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(HostUrl.HOST)
.client(HttpClient.get())
.addConverterFactory(GsonConverterFactory.create())
.build();
api = retrofit.create(AppChannelsApi.class);
}
}
}
return api;
}
}


6,使用Retrofit请求网络。

Call<AppChannels> call = AppChannelsClient.get().getAppCannels();
call.enqueue(new MyCallBack<AppChannels>() {
@Override
public void onSuccess(AppChannels data) {
Log.i(TAG, "size:" + data.getGroups().size() + "  " + data.toString());
mTextView.setText(data.toString());
}

@Override
public void onFailure(Call<AppChannels> call, Throwable t) {

}
});


7,创建自己的CallBack,简化回调参数。

public abstract class MyCallBack<T> implements Callback<T> {
@Override
public void onResponse(Call<T> call, Response<T> response) {
T data = response.body();
if (data != null) {
onSuccess(data);
} else {
onFailure(call, null);
}
}

abstract public void onSuccess(T data);
}


使用Retrofit请求网络就是这么简单,开发者只需要把注意力放在请求网络的接口类和服务器返回的Java Bean就行了。

现在开始分析源码:

public interface AppChannelsApi {

@GET("v2/fm/app_channels")
Call<AppChannels> getAppCannels();
}


可以看到使用了接口,以注解的方式设置网络请求方式,请求参数信息。

可以看得出,Retrofit想动态的获取到注解,请求参数信息,只能通过反射的方式拿到了。

下面分析Retrofit是怎么初始化,怎么拿到这些注解信息的:

public class AppChannelsClient {

private static AppChannelsApi api;

public static AppChannelsApi get() {
if (api == null) {
synchronized (AppChannelsClient.class) {
if (null == api) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(HostUrl.HOST)
.client(HttpClient.get())
.addConverterFactory(GsonConverterFactory.create())
.build();
api = retrofit.create(AppChannelsApi.class);
}
}
}
return api;
}
}


进一步查看Retrofit源码:

静态内部类,Builder

public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;

Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}

public Builder() {
this(Platform.get());
}


可使用链式编程,快速初始化参数

public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}

public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}

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);
}


最终,以Retrofit构造器的形式生成Retrofit对象

public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}

okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

// Make a defensive copy of the adapters and add the default Call adapter.
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);
}


public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

private final okhttp3.Call.Factory callFactory;
private final HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories;
private final List<CallAdapter.Factory> adapterFactories;
private final Executor callbackExecutor;
private final boolean validateEagerly;

Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}


可以看到,Retrofit获取对象的方式,是通过构造者模式。通过构造者这个静态内部类,链式编程的方式快速设置Retrofit参数,

最后将构造者设置的参数,以Retrofit构造器的形式生成Retrofit对象。

接下来,看Retrofit如何使用字节码,生成接口的实现类的。

api = retrofit.create(AppChannelsApi.class);


进入create源码:

public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
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, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}


可以看到,通过动态代理的方式,生成接口的实现了。

接下来看这行代码:

ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);


loadServiceMethod方法,将接口实现类的method字段传递进去,生成一个ServieMethod对象。进入到方法里:

ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}

public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

final class ServiceMethod<T> {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

final okhttp3.Call.Factory callFactory;
final CallAdapter<?> callAdapter;

private final HttpUrl baseUrl;
private final Converter<ResponseBody, T> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;


可以看到,method对象作为Map集合的Key,存储了起来。ServiceMethod是一个Method的包装类。

可以猜的出,ServiceMethod是Retrofit的一次网络请求的具体Java Bean对象。

Retrofit的网络请求,以对象的方式存储到Map集合serviceMethodCache中。

接来下看这行代码:

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);


将一次网络请求的所有信息serviceMethod对象传递给了OkHttpCall,意思是这次网络请求准备交给OkHttp处理。

final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T> serviceMethod;
private final Object[] args;

private volatile boolean canceled;

// All guarded by this.
private okhttp3.Call rawCall;
private Throwable creationFailure; // Either a RuntimeException or IOException.
private boolean executed;

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}


内部可以看到,OkHttpCall拥有一个网络请求serviceMethod

return serviceMethod.callAdapter.adapt(okHttpCall);

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}

final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}

@Override public <R> Call<R> adapt(Call<R> call) {
return call;
}
};
}
}


这行代码会将okHttpCall返回出去。也就是我们自定义接口,方法的返回值:

@GET("v2/fm/app_channels")
Call<AppChannels> getAppCannels();


我们请求网络的时候是这样的:

Call<AppChannels> call = AppChannelsClient.get().getAppCannels();
call.enqueue(new MyCallBack<AppChannels>() {
@Override
public void onSuccess(AppChannels data) {
Log.i(TAG, "size:" + data.getGroups().size() + "  " + data.toString());
mTextView.setText(data.toString());
}

@Override
public void onFailure(Call<AppChannels> call, Throwable t) {

}
});


在OkHttpCall里也有enqueue方法:

@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");

okhttp3.Call call;
Throwable failure;

...


方法里找到:

call = rawCall = createRawCall();

private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}

@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}


可以看到,Retrofit里面的确是通过OkHttpClient进行网络请求的。

okhttp3.Call call = serviceMethod.callFactory.newCall(request);


这个callFactory就行Retrofit外面设置的OkHttpClient对象,只是以接口的方式显示,数据跟踪可以知道。

总的来说,当我们以调用接口实现类的方法:

Call<AppChannels> call = AppChannelsClient.get().getAppCannels();


Retrofit会通过动态代理,获取到接口对象,method字段,再通过反射获取到method字段中的注解,请求参数,

将信息存储到serviceMethod中,一个serviceMethod就包含了一次完整请求网络所需要的数据,

Host,Uri,请求参数,请求类型都有,再通过OkHttp的方式去请求网络,获取到json,

在通过Gson转化工厂将json转化成Java Bean,回调的方式传递出去

这就是Retrofit请求网络的源码分析。

注解 + 反射 + 动态代理 ,依赖OkHttp库。

Retrofit源码分析就到这里。

2016年7月06日 02:35:16
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息