Android网络框架系列: Retrofit2.5(2)

简介: 简介: Retrofit是Square公司开发的一款针对Android网络请求的框架,遵循Restful设计风格,我们查看 invoke 可以发现:底层基于OkHttp实现的 ,相比其他网络请求框架,有以下优势: 性能最好,速度最快(动态代理优势) 简洁易用,代码简化 解耦彻底,职责细分 易与其他框架联用(Rxjava)

四.源码解析

读源码如何开始呢?

我们先带着问题看源码,Retrofit有几个关键的流程

  1. Retrofit 如何将定义的interface转换成网络请求?
  2. Retrofit的Converter机制是如何实现?
  3. Retrofit的CallAdapter机制是如何实现?
1. 寻找入口

  一行一行读,肯定是不可行的,太累了,而且脑容量不够,记不住,合适的读源码方式是从程序入口开始入手。当前功能开始读。

   当前请求的入口发生在enqueue,  那么,我们就开始从这个Api入手读源码.

enqueue, 是进入队列的意思,进去查看,竟然是个

  void enqueue(Callback<T> callback);

如果出现类似抽象方法;就得往回看了,因为读不下去了

2. 寻找接口实现

所以我们往上面找,上面的Api是 enqueue,去找 相关接口实现,找了半天,爱哭,接口实现是GithubService

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<MicroKibacoRepo>> listRepos(@Path("user") String user);
}

而GithubService.java是我自己创建的,怎么办呢? 继续往回看,找呀找, 找到了Retrofit的初始化方法 create,整个源码我就不翻出来了,翻一翻关键的部分,其中需要讲述的APi有:

  • eagerlyValidateMethods
  • newProxyInstance
  • Platform
  • invoke
  • invokeDefaultMethod
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) 
    // --------动态代理--------
    Proxy.newProxyInstance(
    //  提供动态类的实例
    service.getClassLoader(), 
    // 获取 GithubService 的实例,获取需要动态代理类的接口,在 retrofit.create 传入
    new Class<?>[] { service },
    // 
        new InvocationHandler() {
         // 判断接口平台,是JDK 7.0/8.0 或者 Android/IOS
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // 如果这个方法不是直接声明的,那么就直接调用了,兼容性,保护性,不至于越权
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
             // java 8 开始,接口运行有默认的方法实现了
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
    static <T> void validateServiceInterface(Class<T> service) {
     // 1. 验证 GitHubService 是否为一个接口
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
     // 2.验证 GitHubService 是否继承其他接口,只接受原生接口
    if (service.getInterfaces().length > 0) {
      throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
  }
  // 3. 在被初始化的时候,是有一个初始化过程,会去读注解,中间是有耗时的,分布式加载网络请求, validateEagerly 是方便调试的
    private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }

Platform.java 看一下相关实现,里面包含两个平台一个是 Java8 还有一个 Android,这个APi主要是平台标识,知道就行了,没什么好说的

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

loadServiceMethod 里面也没有 invoke,我们通过 parseAnnotations 去找 一下invoke试试看能否找到,

  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.java里面,不过也是一个抽象方法 ,于是我们往回看 parseAnnotations,看里面是否有 invoke 的逻辑实现,找到了,好家伙,parseAnnotations是ServiceMethod子类HttpServiceMethod实现方法,而HttpServiceMethod一定有invoke实现

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.");
    }
// 通过 parseAnnotations 去寻找 invoke实现
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
  abstract T invoke(Object[] args);
}

不用说,我直接在HttpServiceMethod.java, ctr + f 搜,便搜到了invoke,原来底层真是通过OKHttp实现的:

final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
 // ----为了避免浪费篇幅,省略若干无用代码----
 @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
}

上面我说过,看到抽象方法,往回看 ,所以我们来看 okHttpCall,OKHttpCall实现了Call接口 ,重点说一下一下方法:

  • createRawCall
 // OKhttp3的Call帮助Retrofit实现网络请求的Call
  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
  • call.enqueue
     call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      // response 结果交给 Retrofit 使用
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(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();
        }
      }
    });
  }

什么是动态代理?

动态代理是创建一个对象,这个对象传入一个接口并且帮你实现每一个接口的每一个方法,并且这每一个接口的每一个方法都会指向每一个接口每一个方法的invoke方法。

image.png

  • callAdapter

image.png

HttpServiceMethod.java里面的构造方法, 我们找到了 CallAdapter,然后去里面查看是通过 createCallAdapter返回的

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
      // CallAdapter 创建
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }

进入 Retrofit.java 查看一下:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
 // 通过 callAdapterFactories 获取 callAdapter
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
 // ----为了避免浪费篇幅,省略若干无用代码----
  }

callAdaperFactory是通过 Retrofit 的 build 方法构建而来.

  public Retrofit build() {
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

我们看到 callAdaperFactory 通过 addAll 一次性添加过来,所以有我们看一下defaultCallAdapterFactories方法.

    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }

然后我们再看一下 ExecutorCallAdapterFactory

五. 面试题分享

Retrofit请求参数说明

image.png

Retrofit中的设计模式
1. 建造者模式

Retrofit对象的创建、ServiceMethod对象创建都使用Build模式,将复杂对象的创建和表示分离,调用者不需要知道复杂的创建过程,使用Build的相关方法进行配置创建对象。

2. 外观模式

Retrofit对外提供了统一的调度,屏蔽了内部的实现,使得使用该网络库简单便捷。 门面模式: 提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使用子系统更容易使用

image.png

3. 动态代理模式

通过动态代理的方式,当调用Retrofit的create()方法时,会进行动态代理监听。当执行具体的接口方法时,会回调InvocationHandler。通过反射解析method的标注及参数,生成ServiceMethod对象。

4. 静态代理模式

Android平台默认的适配器ExecutorCallbackCall,采用静态代理的模式。具体的实现delegate为OkHttpCall。

5. 工厂模式

Converter及CallAdapter的创建都采用了工厂模式进行创建。

6. 适配器模式

CallAdapter的adapt采用了适配器模式,使得interface的返回对象可以动态扩展,增强了灵活性

CallAdapter的种类

image.png

Converter种类

Retrofit支持多种数据解析方式,使用时需要在Gradle添加依赖。

image.png

Retrofit流程总结

image.png


相关文章
|
1月前
|
监控 安全
从 Racket 语言出发,创新员工网络监控软件的框架
在数字化企业环境中,员工网络监控软件对于保障信息安全和提升效率至关重要。Racket 语言凭借其独特特性和强大功能,为开发创新的监控软件提供了新可能。通过捕获和分析网络数据包、记录员工网络活动日志,甚至构建复杂的监控框架,Racket 能够满足企业的定制化需求,为企业信息安全和管理提供强有力支持。未来,基于 Racket 的创新解决方案将不断涌现。
41 6
|
18天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
60 6
|
26天前
|
机器学习/深度学习 人工智能
类人神经网络再进一步!DeepMind最新50页论文提出AligNet框架:用层次化视觉概念对齐人类
【10月更文挑战第18天】这篇论文提出了一种名为AligNet的框架,旨在通过将人类知识注入神经网络来解决其与人类认知的不匹配问题。AligNet通过训练教师模型模仿人类判断,并将人类化的结构和知识转移至预训练的视觉模型中,从而提高模型在多种任务上的泛化能力和稳健性。实验结果表明,人类对齐的模型在相似性任务和出分布情况下表现更佳。
57 3
|
1月前
|
安全 网络安全 区块链
网络安全与信息安全:构建数字世界的防线在当今数字化时代,网络安全已成为维护个人隐私、企业机密和国家安全的重要屏障。随着网络攻击手段的不断升级,从社交工程到先进的持续性威胁(APT),我们必须采取更加严密的防护措施。本文将深入探讨网络安全漏洞的形成原因、加密技术的应用以及提高公众安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
在这个数字信息日益膨胀的时代,网络安全问题成为了每一个网民不可忽视的重大议题。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全漏洞如同隐藏在暗处的“黑洞”,时刻准备吞噬掉我们的信息安全。而加密技术作为守护网络安全的重要工具之一,其重要性不言而喻。同时,提高公众的安全意识,也是防范网络风险的关键所在。本文将从网络安全漏洞的定义及成因出发,解析当前主流的加密技术,并强调提升安全意识的必要性,为读者提供一份详尽的网络安全指南。
|
2月前
|
存储 SQL 安全
网络安全与信息安全:守护数字世界的坚盾在这个高度数字化的时代,网络安全和信息安全已经成为个人、企业乃至国家安全的重要组成部分。本文将深入探讨网络安全漏洞、加密技术以及安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
随着互联网技术的飞速发展,网络安全问题日益凸显。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全事件层出不穷。本文将从网络安全漏洞的定义与分类入手,探讨常见的网络攻击手段;随后深入解析加密技术的原理及其在保护信息安全中的作用;最后强调提升公众与企业的安全意识的重要性,并提出具体的建议。通过综合运用这些知识点,我们可以更好地构建起一道道坚固的防线,守护我们的数字世界。
|
2月前
|
编解码 分布式计算 网络协议
Netty高性能网络框架(一)
Netty高性能网络框架(一)
|
11天前
|
存储 安全 网络安全
网络安全法律框架:全球视角下的合规性分析
网络安全法律框架:全球视角下的合规性分析
24 1
|
15天前
|
算法 JavaScript Android开发
|
19天前
|
数据采集 前端开发 中间件
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
46 4
|
19天前
|
网络协议 物联网 API
Python网络编程:Twisted框架的异步IO处理与实战
【10月更文挑战第26天】Python 是一门功能强大且易于学习的编程语言,Twisted 框架以其事件驱动和异步IO处理能力,在网络编程领域独树一帜。本文深入探讨 Twisted 的异步IO机制,并通过实战示例展示其强大功能。示例包括创建简单HTTP服务器,展示如何高效处理大量并发连接。
39 1