目录介绍

  • 1.首先回顾Retrofit简单使用方法
  • 2.Retrofit的创建流程源码分析
    • 2.1 Retrofit对象调用Builder()源码解析
    • 2.2 Retrofit对象调用baseUrl(url)源码解析
    • 2.3 addConverterFactory(Converter.Factory factory)源码分析
    • 2.4 addCallAdapterFactory(RxJava2CallAdapterFactory.create())源码分析
    • 2.5 client(okHttpClient)源码分析
    • 2.6 Retrofit对象调用build()源码解析
  • 3.创建ServiceMethod流程源码分析
    • 3.1 首先看看请求网络代码过程
    • 3.2 分析create(final Class<T> service)源码
    • 3.3 serviceMethod对象的创建过程
  • 4.注解的解析
    • 4.1 callAdapter的创建源码分析
    • 4.2 responseConverter的创建源码分析
  • 5.OkHttpCall的创建源码分析
    • 5.1 new OkHttpCall<>(serviceMethod, args)源码分析
  • 6.OkHttpCall的网络请求
    • 6.1 OkHttpCall.execute()同步请求
    • 6.2 OkHttpCall.enqueue()异步请求
    • 6.3 parseResponse解析网络数据源码解析

好消息

  • 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
  • 关于Retrofit的使用,可以参考这篇文章:https://www.jianshu.com/p/989c46a858a4

0.思考问题,针对以下问题,看了这篇博客,应该有了初步的认识

  • 0.0.1 Retrofit创建中用了哪些设计模式,请谈谈使用这些设计模式的优势?
  • 0.0.2 Retrofit在创建的时候为什么要判断是否在Android环境中,是如何做到的?
  • 0.0.3 为什么设置baseUrl的时候,会以/结尾,如果没有/会出现什么问题?
  • 0.0.4 addConverterFactory的主要作用是什么?
  • 0.0.5 Factory生产的是CallAdapter,那么CallAdapter又是什么呢?
  • 0.0.6 网络请求的类 service为什么要定义成接口?如果不定义成接口会出现什么情况?
  • 0.0.7 创建了ServiceMethod对象是干什么用的?它是用什么进行存储的?
  • 0.0.8 创建ServiceMethod对象为什么要添加synchronized同步锁
  • 0.0.9 call调用enqueue异步方法中源码是如何实现异步切换线程的?原理是怎样的?
  • 0.1.0 ServiceMethod是如何保存网络请求所需要的数据,具体保存了哪些数据呢?
  • 0.1.1 网络传输都是二进制流,那么解析数据时,如何通过ServiceMethod使用Converter转换成Java对象进行数据解析
    //AdvertCommon是javabean实体类,并没有序列化,那么网络解析数据如何解析java对象呢?
    Call<AdvertCommon> getSplashImage(@Query("type") int type);
  • 0.1.2 如下所示,为什么说apiService对象实际上是动态代理对象,而不是真正的网络请求接口创建的对象
    ApiService apiService = retrofit.create(ApiService.class);
  • 0.1.3 如何理解动态代理的机制。retrofit是如何加载接口类ApiService的,为什么这个类要设置成接口?

1.首先回顾Retrofit简单使用方法

  • Api接口

    public interface DouBookApi {
    /**
    * 根据tag获取图书
    * @param tag 搜索关键字
    * @param count 一次请求的数目 最多100
    * https://api.douban.com/v2/book/search?tag=文学&start=0&count=30
    */
    @GET("v2/book/search")
    Observable<DouBookBean> getBook(@Query("tag") String tag,
    @Query("start") int start,
    @Query("count") int count);
    }
  • Model类
    public class DouBookModel {
    
        private static DouBookModel bookModel;
    private DouBookApi mApiService; public DouBookModel(Context context) {
    mApiService = RetrofitWrapper
    .getInstance(ConstantALiYunApi.API_DOUBAN) //baseUrl地址
    .create(DouBookApi.class);
    } public static DouBookModel getInstance(Context context){
    if(bookModel == null) {
    bookModel = new DouBookModel(context);
    }
    return bookModel;
    } public Observable<DouBookBean> getHotMovie(String tag, int start , int count) {
    Observable<DouBookBean> book = mApiService.getBook(tag, start, count);
    return book;
    }
    }
  • 抽取类
    public class RetrofitWrapper {
    
        private static RetrofitWrapper instance;
    private Retrofit mRetrofit; public RetrofitWrapper(String url) {
    OkHttpClient.Builder builder = new OkHttpClient.Builder(); //打印日志
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    builder.addInterceptor(logging).build();
    OkHttpClient client = builder.addInterceptor(new LogInterceptor("HTTP")).build(); //解析json
    Gson gson = new GsonBuilder()
    .setLenient()
    .create(); mRetrofit = new Retrofit
    .Builder()
    .baseUrl(url)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .client(client)
    .build();
    } public static RetrofitWrapper getInstance(String url){
    //synchronized 避免同时调用多个接口,导致线程并发
    synchronized (RetrofitWrapper.class){
    instance = new RetrofitWrapper(url);
    }
    return instance;
    } public <T> T create(final Class<T> service) {
    return mRetrofit.create(service);
    }
    }
  • 使用
    DouBookModel model = DouBookModel.getInstance(activity);
    model.getHotMovie(mType,start,count)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<DouBookBean>() {
    @Override
    public void onCompleted() { } @Override
    public void onError(Throwable e) { } @Override
    public void onNext(DouBookBean bookBean) { }
    });
  • 针对Retrofit,需要注意
    • Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装。看下图所示,摘自网络

2.Retrofit的创建流程源码分析

2.1 Retrofit对象调用Builder()源码解析

  • 首先看看里面的源代码,如下所示

    • 可以看到Platform.get()获取的是单利对象。那么也许你会问,这个方法的作用主要是什么呢?通过Class.forName获取类名的方式,来判断当前的环境是否在Android中,这在之后获取默认的CallAdapterFactory时候将会用到。下面我会分析到……
    • 关于单利设计模式,如果还有疑问,或者想知道所有的获取单利的方法,可以参考我的这篇博客:设计模式之一:单例模式
    //第一步
    public Builder() {
    this(Platform.get());
    } //第二步,追踪到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) {
    //此处表示:如果是Android平台,就创建并返回一个Android对象
    return new Android();
    }
    } catch (ClassNotFoundException ignored) {
    }
    try {
    Class.forName("java.util.Optional");
    return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
    }
  • 然后看一下new Android()是做了什么?
    static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
    // 返回一个默认的回调方法执行器
    // 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
    return new MainThreadExecutor();
    } @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    // 创建默认的网络请求适配器工厂
    // 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
    // 采用了策略模式
    return new ExecutorCallAdapterFactory(callbackExecutor);
    } static class MainThreadExecutor implements Executor {
    // 获取与Android 主线程绑定的Handler
    private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) {
    // 该Handler是上面获取的与Android 主线程绑定的Handler
    // 在UI线程进行对网络请求返回数据处理等操作。
    handler.post(r);
    }
    }
    }

2.2 Retrofit对象调用baseUrl(url)源码解析

  • 都知道这个方法主要是设置baseUrl。源码如下所示

    • 首先先对baseUrl进行非空判断。然后再解析baseUrl,如果解析的httpUrl为null,则会抛出IllegalArgumentException非法参数异常。那么思考一下,什么情况下解析baseUrl会导致解析内容httpUrl为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);
    }
  • HttpUrl是如何解析url,对url有什么条件,来看一下parse方法源码
    • 可以看到url必须是以http或者https才可以。如果随便写一个url,则会出问题
    public static @Nullable HttpUrl parse(String url) {
    Builder builder = new Builder();
    Builder.ParseResult result = builder.parse(null, url);
    return result == Builder.ParseResult.SUCCESS ? builder.build() : null;
    } ParseResult parse(@Nullable HttpUrl base, String input) {
    int pos = skipLeadingAsciiWhitespace(input, 0, input.length());
    int limit = skipTrailingAsciiWhitespace(input, pos, input.length()); // Scheme.
    int schemeDelimiterOffset = schemeDelimiterOffset(input, pos, limit);
    if (schemeDelimiterOffset != -1) {
    if (input.regionMatches(true, pos, "https:", 0, 6)) {
    this.scheme = "https";
    pos += "https:".length();
    } else if (input.regionMatches(true, pos, "http:", 0, 5)) {
    this.scheme = "http";
    pos += "http:".length();
    } else {
    return ParseResult.UNSUPPORTED_SCHEME; // Not an HTTP scheme.
    }
    } else if (base != null) {
    this.scheme = base.scheme;
    } else {
    return ParseResult.MISSING_SCHEME; // No scheme.
    } //下面代码省略了
  • 思考一下,传递的url为什么是String BASE_URL = "http://beta.goldenalpha.com.cn/"这个格式呢?接着看看baseUrl(httpUrl)源码
    • 可以看到这里的url地址必须是以/结尾。所以如果是没有加上/,则会出现异常
    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;
    }
  • 其实个人感觉这块工作并不难,只要有点英文基础的,就可以完全看的明白。接着往下分析,如果想了解更多,欢迎看我的博客汇总:https://github.com/yangchong211/YCBlogs

2.3 addConverterFactory(Converter.Factory factory)源码分析

  • 在创建的时候会调用addConverterFactory(GsonConverterFactory.create(JsonUtils.getJson()))添加Gson转换器

    • 这个方法主要是添加用于对象序列化和反序列化的转换器工厂
    • 将上面创建的GsonConverterFactory放入到 converterFactories数组
    .addConverterFactory(GsonConverterFactory.create(JsonUtils.getGson()))
    
    //看这行代码
    public Builder addConverterFactory(Converter.Factory factory) {
    //将上面创建的GsonConverterFactory放入到 converterFactories数组
    converterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
    }
  • 然后看看GsonConverterFactory.creat()方法源码
    • 使用{@code gson}创建一个实例以进行转换。编码到JSON并从JSON解码(当没有由头指定字符集时)将使用UTF-8。
    • 创建了一个含有Gson对象实例的GsonConverterFactory,并返回给addConverterFactory()
    public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
    }

2.4 addCallAdapterFactory(RxJava2CallAdapterFactory.create())源码分析

  • 添加一个调用适配器工厂,用于支持服务方法返回类型

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
    callAdapterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
    }
  • CallAdapterFactory:注意Factory生产的是CallAdapter,那么CallAdapter又是什么呢?
    • 可以看到CallAdapter源代码如下所示,它是一个接口。主要作用是:将响应类型{@代码R}的{@链接调用}改编为{@代码T}的类型。实例由{@LinkplanFactory(一个工厂)创建,该工厂}是{@Link平原Retrofit.Builder#addCallAdapterFactory(Factory)已安装}到{@LinkRetroflit}实例中。
    • 网络请求执行器(Call)的适配器,并且在Retrofit中提供了三种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、DefaultCallAdapterFactory、RxJava2CallAdapterFactory
    public interface CallAdapter<R, T> {
    Type responseType();
    T adapt(Call<R> call);
    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);
    }
    }
    }
  • 接着,有伙伴可能会问它的作用是什么呢?
    • 将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
    • 一开始Retrofit只打算利用OkHttpCall通过ExecutorCallbackCall切换线程;但后来发现使用Rxjava更加方便(不需要Handler来切换线程)。想要实现Rxjava的情况,那就得使用RxJavaCallAdapterFactoryCallAdapter将OkHttpCall转换成Rxjava(Scheduler)
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

2.5 client(okHttpClient)源码分析

  • 用于请求的HTTP客户端

    • 指定用于创建{@link Call}实例的自定义调用工厂。
    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;
    }

2.6 Retrofit对象调用build()源码解析

  • 看看源码

    • 大概的流程就是创建适配器的防御性副本,并添加默认调用适配器。然后复制转换器的防御性副本,在然后添加内置的转化工厂.这可以防止重写其行为,但也可以确保在使用消耗所有类型的转换器时的正确行为。
    • 通过前面步骤设置的变量,将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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories =
    new ArrayList<>(1 + this.converterFactories.size()); // 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());
    converterFactories.addAll(this.converterFactories); return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
    unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  • 然后看看Retrofit的构造方法
    • 成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量,即配置好:

      • serviceMethod:包含所有网络请求信息的对象
      • baseUrl:网络请求的url地址
      • callFactory:网络请求工厂
      • adapterFactories:网络请求适配器工厂的集合
      • converterFactories:数据转换器工厂的集合
      • callbackExecutor:回调方法执行器
    Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
    List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
    @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
    }
  • 然后总结一下创建的过程
    • 平台类型对象(Platform - Android)
    • 网络请求的url地址(baseUrl)
    • 网络请求工厂(callFactory) 默认使用OkHttpCall
    • 网络请求适配器工厂的集合(adapterFactories) 本质是配置了网络请求适配器工厂- 默认是ExecutorCallAdapterFactory
    • 数据转换器工厂的集合(converterFactories) 本质是配置了数据转换器工厂
    • 回调方法执行器(callbackExecutor) 默认回调方法执行器作用是:切换线程(子线程 - 主线程)

3.创建ServiceMethod流程源码分析

3.1 首先看看请求网络代码过程

  • 大概的流程如下代码所示

    • 定义网络请求的接口类 ApiService
    public interface ApiService {
    @POST("api/v1/user/old")
    Call<ResEntity<UserOld>> isUserOld();
    } //创建接口类实例
    ApiService apiService = retrofit.create(ApiService.class);
    //生成最终的网络请求对象
    Call<ResEntity<UserOld>> userOld = apiService.isUserOld();
    //异步机制
    userOld.enqueue(new Callback<ResEntity<UserOld>>() {
    @Override
    public void onResponse(Call<ResEntity<UserOld>> call, retrofit2.Response<ResEntity<UserOld>> response) { }
    @Override
    public void onFailure(Call<ResEntity<UserOld>> call, Throwable t) { }
    });

3.2 分析create(final Class<T> service)源码

  • 源代码如下所示,这段代码很重要。

    • 创建接口定义的API端点的实现。给定方法的相对路径是从描述请求类型的方法的注释中获得的。
    • 先对service类进行判断是否是接口。这个时候你就知道为何只能定义service为接口呢……
    • 接着就创建了ServiceMethod对象,并且把这个对象以键的形式存储到ConcurrentHashMap集合中
    • 最后创建了网络请求接口的动态代理对象,通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler类 作为具体的实现,并最终返回一个动态代理对象。
      • service.getClassLoader()作用是动态生成接口的实现类
      • new Class<?>[] { service }作用是动态创建实例
      • new InvocationHandler()作用是将代理类的实现交给 InvocationHandler类作为具体的实现
    • 即通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke方法来完成指定的功能
    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, @Nullable 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<Object, Object> serviceMethod =
    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    //根据配置好的serviceMethod对象创建okHttpCall对象
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    //调用OkHttp,并根据okHttpCall返回rejava的Observe对象或者返回Call
    return serviceMethod.adapt(okHttpCall);
    }
    });
    }
  • 接着看一下validateServiceInterface方法操作了什么?
    • 通过这个方法可知,如果service类不是接口则会抛异常。同时需要注意API接口不能扩展其他接口
    static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
    throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
    // Android (http://b.android.com/58753) but it forces composition of API declarations which is
    // the recommended pattern.
    if (service.getInterfaces().length > 0) {
    throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
    }
  • 接着看看eagerlyValidateMethods这个方法的源码
    • 判断是否需要提前验证,主要是给接口中每个方法的注解进行解析并得到一个ServiceMethod对象,然后以Method为键将该对象存入serviceMethodCache集合中。该集合是一个ConcurrentHashMap集合。
    • 关于ConcurrentHashMap集合的源码分析,可以参考我的这篇博客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();
    serviceMethodCache.put(method, result);
    }
    }
    return result;
    }
  • 知道return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)通过代理模式中的动态代理模式,在面试中也经常会问到该模式,那么该模式有什么特点呢?
    • 当NetService对象调用getCall()接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理
    • 获得网络请求接口实例上的所有注解
  • 接着看看loadServiceMethod(Method method)方法源码
    • 可以看到先从serviceMethodCache集合中获取result对象,然后对result进行非空判断
    • 并且通过synchronized关键字设置了线程同步锁,创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例,若没缓存,则通过建造者模式创建 serviceMethod 对象。创建实例的缓存机制:采用单例模式从而实现一个 ServiceMethod 对象对应于网络请求接口里的一个方法
    • 针对synchronized关键字的作用可以参考我的这篇博客:https://blog.csdn.net/m0_37700275/article/details/83151850
    • 针对单利设计模式总结笔记:https://blog.csdn.net/m0_37700275/article/details/78276558

3.3 serviceMethod对象的创建过程

  • 创建之前,首先会尝试根据方法从一个缓存列表中取出ServiceMethod实例,如果没有,在锁保护之后,还有再尝试一次,还是没有的情况下,才会去创建ServiceMethod。

  • 第一步,先看看ServiceMethod的Builder方法
    • 除了传递了两个参数外,还获取网络请求接口方法里的注释,获取网络请求接口方法里的参数类型,获取网络请求接口方法里的注解内容
    Builder(Retrofit retrofit, Method method) {
    this.retrofit = retrofit;
    this.method = method;
    this.methodAnnotations = method.getAnnotations();
    this.parameterTypes = method.getGenericParameterTypes();
    this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
  • 第二步,然后看看ServiceMethod的build()方法
    • 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器callAdapter对象
    • 网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型responseType
    • 然后对responseType类型进行判断,如果是Response类型或者okhttp3.Response类型,则抛出异常
    • 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器responseConverter对象
    • 然后采用for循环解析网络请求接口中方法的注解,注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTT等等
    • 如果httpMethod为null。则抛出异常
    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(); for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
    } if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
    } if (!hasBody) {
    if (isMultipart) {
    throw methodError(
    "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
    throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
    + "request body (e.g., @POST).");
    }
    } 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);
    } Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
    throw parameterError(p, "No Retrofit annotation found.");
    } parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
    } if (relativeUrl == null && !gotUrl) {
    throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
    }
    if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError("Non-body HTTP method cannot contain @Body.");
    }
    if (isFormEncoded && !gotField) {
    throw methodError("Form-encoded method must contain at least one @Field.");
    }
    if (isMultipart && !gotPart) {
    throw methodError("Multipart method must contain at least one @Part.");
    } return new ServiceMethod<>(this);
    }
  • 第三步,看看ServiceMethod(Builder<R, T> builder) 构造方法
    • 可以看到这里都是参数赋值操作
    ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
    }

4.注解的解析

4.1 callAdapter的创建源码分析

  • 首先获取method的对象表示的方法的形式类型。然后获取method的注解。重点看看retrofit.callAdapter(returnType, annotations)主要做了什么?

    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(returnType, annotations)源码
    public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
    } public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null"); int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
    return adapter;
    }
    } StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
    .append(returnType)
    .append(".\n");
    if (skipPast != null) {
    builder.append(" Skipped:");
    for (int i = 0; i < start; i++) {
    builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    builder.append('\n');
    }
    builder.append(" Tried:");
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
    }

4.2 responseConverter的创建源码分析

5.OkHttpCall的创建源码分析

5.1 new OkHttpCall<>(serviceMethod, args)源码分析

  • 可以看到创建OkHttpCall对象需要两个参数,参数分别是配置好的ServiceMethod对象和输入的请求参数

    • 源码如下所示
    final class OkHttpCall<T> implements Call<T> {
    private final ServiceMethod<T, ?> serviceMethod;
    private final @Nullable Object[] args; OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    //含有所有网络请求参数信息的对象
    this.serviceMethod = serviceMethod;
    //网络请求接口的参数
    this.args = args;
    }
    }
  • 接着看看return serviceMethod.adapt(okHttpCall)源码分析
    • 创建的OkHttpCall对象传给第一步创建的serviceMethod对象中对应的网络请求适配器工厂的adapt()
    • 返回对象类型:Android默认的是Call<>;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>。如果这个地方不理解,可以继续往下看
    T adapt(Call<R> call) {
    return callAdapter.adapt(call);
    }
  • 接着看看实际的调用
    • ApiService对象实际上是动态代理对象Proxy.newProxyInstance(),并不是真正的网络请求接口创建的对象
    • 当ApiService对象调用isUserOld()时会被动态代理对象Proxy.newProxyInstance()拦截,然后调用自身的InvocationHandler # invoke()
    • invoke(Object proxy, Method method, Object... args)会传入3个参数:Object proxy:(代理对象)、Method method(调用的isUserOld()),Object... args(方法的参数,即getCall(*)中的)
    • 接下来利用Java反射获取到isUserOld()的注解信息,配合args参数创建ServiceMethod对象。
    • 最终创建并返回一个OkHttpCall类型的Call对象或者Observable
      • OkHttpCall类是OkHttp的包装类
      • 创建了OkHttpCall类型的Call对象还不能发送网络请求,需要创建Request对象【也就是异步请求方法】才能发送网络请求
    ApiService apiService = retrofit.create(ApiService.class);
    //返回Android默认的Call
    Call<ResEntity<UserOld>> userOld = apiService.isUserOld(); //返回的则是Observable<T>
    Observable<AdvertCommon> advert = mApiService.getSplashImage(method)

6.OkHttpCall的网络请求

6.1 OkHttpCall.execute()同步请求

  • 使用方法Response<Bean> response = call.execute();

    • 实际开发中这种我也没有用过……哈哈
    • 首先添加一个synchronized同步锁。先创建一个OkHttp的Request对象请求,然后调用OkHttpCall的execute()发送网络请求,再然后解析网络请求返回的数据。
    • 需要注意:
      • 发送网络请求时,OkHttpCall需要从ServiceMethod中获得一个Request对象
      @Override public Response<T> execute() throws IOException {
    okhttp3.Call call; synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true; if (creationFailure != null) {
    if (creationFailure instanceof IOException) {
    throw (IOException) creationFailure;
    } else if (creationFailure instanceof RuntimeException) {
    throw (RuntimeException) creationFailure;
    } else {
    throw (Error) creationFailure;
    }
    } call = rawCall;
    if (call == null) {
    try {
    call = rawCall = createRawCall();
    } catch (IOException | RuntimeException | Error e) {
    throwIfFatal(e); // Do not assign a fatal error to creationFailure.
    creationFailure = e;
    throw e;
    }
    }
    } if (canceled) {
    call.cancel();
    } return parseResponse(call.execute());
    } //从serviceMethod一个Request对象
    private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
    }

6.2 OkHttpCall.enqueue()异步请求

  • 关于异步操作封装库,可以看我的开源线程池封装库:https://github.com/yangchong211/YCThreadPool
  • 如何调用可以看前面的代码介绍。这里就不介绍呢!
    • 首先添加一个synchronized同步锁。创建OkHttp的Request对象,然后发送网络请求,然后解析返回数据。在这里,可能会想到,究竟是如何做到异步操作的呢?
      @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(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 {
    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 {
    response = parseResponse(rawResponse);
    } catch (Throwable e) {
    callFailure(e);
    return;
    } try {
    callback.onResponse(OkHttpCall.this, response);
    } catch (Throwable t) {
    t.printStackTrace();
    }
    } @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) {
    t.printStackTrace();
    }
    }
    });
    } private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
    }
  • 从上可以知道,call操作异步,那么这个call是什么呢?那么我们看一下ExecutorCallAdapterFactory这个类,关于CallAdapterFactory是做什么用的?前面已经介绍呢!
    • 如果你对异步线程还不是很熟悉,可以参考我的线程池封装库,里面已经很详细实现了异步线程操作,参考链接:https://github.com/yangchong211/YCThreadPool
    • 线程切换,即将子线程切换到主线程,从而在主线程对返回的数据结果进行处理
    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) {
    checkNotNull(callback, "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);
    }
    });
    }
    });
    }

6.3 parseResponse解析网络数据源码解析

  • 解析网络数据

    • 关于网络状态栏,我已经整理了一篇十分详细的博客,可以看我的这篇文章:07.Http状态码详解
    • 调用serviceMethod.toResponse(catchingBody),解析数据时,还需要通过ServiceMethod使用Converter(数据转换器)转换成Java对象进行数据解析
    • 关于网络请求的基础介绍,可以参考我的这篇博客:https://blog.csdn.net/m0_37700275/article/details/78533930
      Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
    .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
    .build(); int code = rawResponse.code();
    if (code < 200 || code >= 300) {
    try {
    // Buffer the entire body to avoid future I/O.
    ResponseBody bufferedBody = Utils.buffer(rawBody);
    return Response.error(bufferedBody, rawResponse);
    } finally {
    rawBody.close();
    }
    } if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
    } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
    // If the underlying source threw an exception, propagate that rather than indicating it was
    // a runtime exception.
    catchingBody.throwIfCaught();
    throw e;
    }
    }

关于其他内容介绍

01.关于博客汇总链接

02.关于我的博客

Retrofit源码分析的更多相关文章

  1. Retrofit源码分析(一)

    1.基本用法 创建接口 public interface GitHubService { @GET("users/{user}/repos") Observable<List ...

  2. [置顶] 【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的

    一.简介 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明白为什么Retrofit那么屌.最近也看了一些其源码分析的文章以及亲自查看了源码,发现其对 ...

  3. [旧][Android] Retrofit 源码分析之 ServiceMethod 对象

    备注 原发表于2016.05.03,资料已过时,仅作备份,谨慎参考 前言 大家好,我又来学习 Retrofit 了,可能这是最后一篇关于 Retrofit 框架的文章了.我发现源码分析这回事,当时看明 ...

  4. [旧][Android] Retrofit 源码分析之执行流程

    备注 原发表于2016.04.23,资料已过时,仅作备份,谨慎参考 前言 由于是第一次自己翻看源代码进行学习,加上基础不好,在看源代码的过程中简直痛苦不堪,但同时也暴露出了自己的许多问题.我觉得学习源 ...

  5. [旧][Android] Retrofit 源码分析之 Retrofit 对象

    备注 原发表于2016.04.27,资料已过时,仅作备份,谨慎参考 前言 在上一周学习了一下 Retrofit 的执行流程.接下来的文章要更为深入地学习 Retrofit 的各个类,这次我们先学习一下 ...

  6. 源码分析Retrofit请求流程

    Retrofit 是 square 公司的另一款广泛流行的网络请求框架.前面的一篇文章<源码分析OKHttp执行过程>已经对 OkHttp 网络请求框架有一个大概的了解.今天同样地对 Re ...

  7. Android网络框架源码分析一---Volley

    转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium ...

  8. Retrofit源码设计模式解析(上)

    Retrofit通过注解的方法标记HTTP请求参数,支持常用HTTP方法,统一返回值解析,支持异步/同步的请求方式,将HTTP请求对象化,参数化.真正执行网络访问的是Okhttp,Okhttp支持HT ...

  9. Retrofit2源码分析(一)

    本文将顺着构建请求对象→构建请求接口→发起同步/异步请求的流程,分析retrofit2是如何实现的. 组成部分 Retrofit2源码主要分为以下几个部分: retrofit retrofit-ada ...

  10. springcloud 入门 5 (feign源码分析)

    feign:(推荐使用) Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目. Feign的主要目标是将Java Http ...

随机推荐

  1. 用superxmlparser.pas的XMLParseString----XML转Json注意

    了解XML转成Json时候用的时候多了个#号: ---------------------------------------------------------------------------- ...

  2. linux 测试网络速率

    1. ethtool ethtool是很强大的查询网卡(嵌入式称为phy芯片)配置的工具,几乎phy芯片芯片手册寄存器能配置的选项,ethtool都能查询到:嵌入式调试phy芯片的时候经常用到该命令: ...

  3. 云原生服务网格Istio:原理、实践、架构与源码解析

    华为云原生团队600多页的Istio实战精华总结,云原生服务网格Istio:原理.实践.架构与源码解析的电子书. 图书介绍 <云原生服务网格Istio:原理.实践.架构与源码解析>分为原理 ...

  4. STC8A8K64S4A12内部时钟的IRTRIM和LIRTRIM简单标定

    STC8A8K64S4A12因为没有固化的频率调节值, 要么在STC-ISP烧录时设置写入, 要么通过idata高地址读取, 这对于Linux下的SDCC用户就非常不方便, 既不能用STC-ISP, ...

  5. 执行shell脚本过程中传递参数

    假设我有一个shell脚本install.sh,在运行过程中需要终端输入一条指令才能继续执行,例如程序询问是否删除某文件,终端需要输入Y/N.采用下面的方式可以实现自动输入参数,无需人工干预: ech ...

  6. 【Android逆向】破解看雪9月算法破解第三题

    这题的目标是算法还原,并写出注册机 1. 9月份算法第一题.apk 安装到手机 2. 随意输入账号密码,提示错误 3. apk拖入到jadx中 public native boolean regist ...

  7. python列表操作的大O效率

  8. 工作中django的应用路径配置

    1.通常工作中都会把所有的应用放在一个主目录中 比如:主项目文件夹为luffyapi 在luffyapi下创建一个apps文件夹,用来存放所有的app应用 2.创建应用 先创建一个应用,需要cd到ap ...

  9. JVM-对象实例化

    JVM-对象实例化 1.创建对象的方式 new:最常见的方式.Xxx的静态方法,XxxBuilder/XxxFactory的静态方法 Class的newInstance方法:反射的方式,只能调用空参的 ...

  10. 第一百零四篇:DOM事件流

    好家伙,JS基础接着学,   1.事件流 页面哪个部分拥有特定的事件? 可以把页面想象成一个同心圆, 当你戳了其中的一点,其实你同时戳中了很多个圆   当你点击一个页面中的按钮,实际上你同时点击了这个 ...