您的位置:首页 > 其它

Retrofit2 源码分析

2017-05-04 15:54 260 查看
在gradle配置里面是中增加对retrofit的引用。compile[b]'com.squareup.retrofit2:retrofit:2.2.0'[/b]这篇文章主要分析下retrofit2框架的底层原理。我下载到的是2.2.0的版本。

一.如何使用Retrofit

首先看一下Retrofit是怎么用的。public interface GithubService{
@GET("user/{user}/repos")
Call<List<ResponseBody>> listRpo(@Path("user") String user)
}

Retrofit tetrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.baseUrl("https://www.github.com/")
.build();
GithubService service = tetrofit.create(GithubService.class)
Call<List<ResponseBody>> call = service.listRpo("octocat");

call.enqueue(new Callback<List<ResponseBody>>() {
@Override
public void onResponse(Call<List<ResponseBody>> call, Response<List<ResponseBody>> response) {
String result = response.getBody();
}

@Override
public void onFailure(Call<List<ResponseBody>> call, Throwable t) {
Log.d("TAG",t.getMessage());
}
});
使用retrofit需要先创建一个interface接口,这个接口其实声明了网络请求的地址,参数,返回类型,请求方式等等。
这个接口在retrofit的转化下转化成网络请求。 Retrofit的接口支持以下功能:
1.@GET 和 @Post支持切换请求方式
2.@Path支持请求格式的动态变化,@Header用于添加不固定的Header
3.支持FormUrlEncoded和Multipart等标记
Retrofit访问网络时,大概分为1.构建网络请求 2.发送网络请求 两步骤。
1.构建网络请求——创建一个Retrofit类,这个Retrofit类是用建造者模式构建的。client()方法指定了底层是用okhttp进行通讯,baseUrl()方法指定 访问的URL是www.github.com。然后获得GithubService对象,这个GithubService对象其实就是我们自己定义的接口类,Retrofit会自动将我们定义的接口类转化成网络请求。 
2.发送网络请求——得到call对象,执行call对象。

[b]二.构建网络请求[/b]

接下来从源码的角度来分析一下内部原理,首先来看一下Retrofit类。public final class Retrofit {

private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final Executor callbackExecutor;
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;
}
最核心的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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

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();
serviceMethodCache.put(method, result);
}
}
return result;
}
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);
}

先来看一下build方法,调用Retrofit.build的build方法会生成一个Retrofit对象,通过建造者模式(建造者模式:构建和使用相分离)传递给它callFactory, baseUrl, converterFactories, adapterFactories这些参数,callFacotry是你网络请求采用的底层通信,比如采用okhttp请求,baseUrl表示请求的地址,converterFactories表示转换器,adapterFactories是适配转换器。
接下来是create()方法,在create方法中首先会进行判断所传入进来的Service是否是一个接口,当我们将validateEagerly属性设为true的时候,在我们调用create方法创建一个Service,就直接调用eagerlyValidateMethods方法里面。eagerlyValidateMethods有什么作用呢?它通过反射获取获们创建service接口中所有的接口方法,然后根据接口方法和当前的retrofit对象来获得ServiceMethod并且以接口方法作为Key,ServiceMethod作为值添加到serviceMethodCache缓存中。这样做的目的是为了下次便可以通过接口方法直接获取ServiceMethod。这就是 eagerlyValidateMethods的作用。继续分析create方法里面的代码,接着往下看
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
所以,很明显的,这里用到了java的动态代理,java动态代理的作用是将这个在一段代码的方法执行前插入一段执行的代码。

因为retrofit底层是用java动态代理实现的,所以在这里有必要先弄懂java动态代理的机制。关于java的动态机制,网上有很多比较好的文章,这里也有一篇文章推荐。 那么,当我们通过自己创建的接口去调用接口方法时,这时候动态代理会去先执行invoke方法。那么究竟利用动态代理invoke了什么代码呢?在InvocationHandler的invoke方法里面,我们可以看到执行了下面的代码。ServiceMethod<Object, Object> serviceMethod =  (ServiceMethod<Object, Object>) loadServiceMethod
(method);  
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);         
 return serviceMethod.callAdapter.adapt(okHttpCall);
这三句代码是整个retrofit的核心代码。ServiceMethod是干嘛的?ServiceMethod负责将自定义接口转化为实际的http请求。
然后再调用servicemehtod的calladapter当中的adapt方法进行初始化。
也就是说当我们调用自己实现接口的方法时,Retrofit利用create方法然后通过java动态放射的方式去调用servicemethod当中的calladapter当中的adapt方法进行初始化。
这样就得到的动态代理接口看起来是上面自己实现的GithubService,但是通过java动态代理会将这个GithubService在调用方法时转化为真正的http请求。
首先,通过loadServceMethod方法从这个缓存当中获取ServiceMethod。
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();
serviceMethodCache.put(method, result);
}
}
return result;
}

loadServceMethod方法首先去缓存里面去取ServcieMethod,如果没有,调用ServiceMehtod的build()方法。
public ServiceMethod build() {
callAdapter = createCallAdapter();
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?");
}
responseConverter = createResponseConverter();

...//省略代码   return new ServiceMethod<>(this);
}

这个方法返回一个新的ServiceMethod,并且创建了 calladapter对象。看一下calladapter是怎么创建的。 private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}里面是调用了Retrofit类的callAdapter方法。

/**
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

原来createCallAdapter里面默认遍历了Retrofit的adapterFactories,但是Retrofit当中有哪些CallAdapter呢?回过头来再去看Retrofit类的build方法,Retrofit类在build方法中返回一个默认的defaultCallAdapterFactory。if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
也就是说,不管Retrofit有没有往adapterFactories里面增加CallAdapter对象,都有一个默认的defaultCallAdapterFactory。Retrofit在创建的时候,默认的callFactory是OKHttpClient,默认的callbackexecutrot是platform.defaultCallbackExecutor();platform是一个retrofit里面表示当前平台的接口,在Android设备中,这个paltform是一个Android类里实现的,我们在下面这段代码中找到了这个defaultCallbackExecutor.class Platform {
private static final Platform PLATFORM = findPlatform();

static Platform get() {
return PLATFORM;
}

private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}

@Nullable Executor defaultCallbackExecutor() {
return null;
}

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
通过分析上面的源代码,这里不难理解,platform对象默认返回的是Android对象,所以我们再看一下Android类的代码 static class Android extends Platform {
   

@Override
public Executor defaultCallbackExecutor() {     
return new MainThreadExecutor();   }   

@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {     
return new ExecutorCallAdapterFactory(callbackExecutor);   }   

static class MainThreadExecutor implements Executor {     
private final Handler handler = new Handler(Looper.getMainLooper());     

@Override
public void execute(Runnable r) {       handler.post(r);     }   

}
   看defaultCallAdapterFactory这个方法返回的是ExecutorCallAdapterFactory我们看一下ExecutorCallAdapterFactory的源码。@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<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
得出结论:serviceMethod.callAdapter.adapt(okHttpCall); 最终返回了一个ExecutorCallbackCall。

三,发送网络请求

GithubService service = tetrofit.create(GithubService.class)Call<List<ResponseBody>> call = service.listRpo("octocat");执行service的xxxx方法,java动态代理帮助我们构建了一个完整的http请求。最后返回一个Call对象。上面我们说了,动态代理执行的时候会返回一个ExecutorCallbackCall,我们来看一下它的源代码。

static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}

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

delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}

@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}

@Override public boolean isExecuted() {
return delegate.isExecuted();
}

@Override public Response<T> execute() throws IOException {
return delegate.execute();
}

ExecutorCallbackCall有enqueue和execute方法,但是具体里面都是交给delegate对象去执行的。那么这个delegate对象又是什么呢?就是serviceMethod.callAdapter.adapt(okHttpCall)里面的okHttpCall,一个实现了Call接口的OkHttpCall对象。看到这里是不是有一种恍然大悟的感觉,如此我们只要研究下OkHttpCall对象就行了。OkHttpCall对象是访问请求的对象,默认的作用是发送一个HTTP请求,底层是使用了okhttp进行网络通讯。如此一来也就明白了Retrofit说到底只是对okhttp的一层层封装而已。privateokhttp3.Call createRawCall()throwsIOException {
Request request =serviceMethod.toRequest(args);
okhttp3.Call call =serviceMethod.callFactory.newCall(request);
if(call == null) {
throw newNullPointerException("Call.Factory returned null.");
}
return call;
}

OkHttpCall实现了enqueue和execute方法,这两个方法是真正网络请求发起的方法,都通过调用createRawCall()来创建请求。execute方法是在当前线程执行,将具体执行的动作交给android的okhttp去完成,调用了okhttp3.Call.execute()函数。    enqueue方法是将请求放到一个异步线程队列当中。调用okhttp3.Call.enqueue()函数。retrofit底层还是调用okhttp来实现的。Ps:可以参考下HttpCall里面的execute方法@OverridepublicResponse<T> execute() throwsIOException {
okhttp3.Call call;

synchronized(this) {
if(executed)throw newIllegalStateException("Already executed.");
executed=true;

if(creationFailure!=null) {
if(creationFailureinstanceofIOException) {
throw(IOException)creationFailure;
}else{
throw(RuntimeException)creationFailure;
}
}

call =rawCall;
if(call ==null) {
try{
call =rawCall= createRawCall();
}catch(IOException | RuntimeException e) {
creationFailure= e;
throwe;
}
}
}

if(canceled) {
call.cancel();
}

returnparseResponse(call.execute());
}

四,支持报文解析

Retrofit还支持Gson、xml格式报文解析 。比如我们想加入gson格式的解析,只需在构建的时候调用addConvertFactory方法。Retrofit retrofit = new Retrofit.Builder().
baseUrl('https://api.github.com').
.addConvertFacotry(GsonConverterFactory.create()) //支持报文自动解析
.build
然后构建网络请求:
final MehtodService methdoservice = retrofit.create(MehtodService.s);
发起网络请求
Call<Bean> call = methdoservice.getMsg();GsonConverterFacotry会自动解析你接受的gson格式的报文,在调用网络请求后,转化成为这里的Bean。Bean类里面的字段和Gson报文返回的字段应该一样。如果字段不一样,会在解析的时候抛出解析异常。这里补充引用的类库:如果想要增加对xml解析器的支持:
compile(‘com.squareup.retrofit2:converter-simplexml:2.1.0’);
如果想要增加对gson格式解析器的支持:
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
如果想要增加对rxjava的支持:
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
 也可以通过实现Converter.Factory接口来创建一个自定义的converter。addConvertFacotry里面的操作就是往Retrofit这个类中增加Converter.Factory接口. 
这个Converter对象是什么时候创建的?首先我们在构建Retrofit的时候传了一个GsonConverterFactory.create(),然后会在ServiceMethod的build()的时候将我们创建的Converter加入进去.关键代码如下:public ServiceMethod build() {
callAdapter = createCallAdapter();
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?");
}
responseConverter = createResponseConverter();
。。。
}关键是执行了createResponseConverter()方法,然后查看你createResponseConverter方法private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
主要执行了responseBodyConverter方法。找到responseBodyConverter方法再看一下()。public<T> Converter<ResponseBody, T>responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
看下nextResponseBodyConverter()这里面的逻辑。
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
。。。
}

关键是执行了从converterFactories当中查找到对应的factory,然后执行responseBodyConverter方法,这个方法如果是自定义的Converter.Factory,就是自定义解析报文格式的话,必须得自己实现这个方法。

 五,其他

Retrofit2支持了RxJava的使用。这部分内容也很多,这里篇幅有限,不再拓展开来了。Retrofit是一款热门的网络请求架构,拓展性非常好。理解这样的开源框架的源码,有助于我们扩展视野,以及更好解决在实际开发过程当中所遇到的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: