网络架构-Retrofit下(源码分析)

网络架构-Retrofit下(源码分析)

Android小彩虹2021-07-13 5:04:31130A+A-

前言

相信作为一个安卓开发者,基本上对retrofit的使用都掌握了,但是实现的背后原理了解吗?

使用流程

  • 1、创建retrofit实例
  • 2、创建网络请求接口并配置相应方法注解及参数注解
  • 3、通过动态代理实现网络请求接口实例
  • 4、调用网络请求接口实例的方法获取网络执行器
  • 5、发生网络请求,并通过数据转换器针对服务器返回的数据进行解析
  • 6、通过回调执行器将数据切换到主线程,交给用户处理

例子

 public static Retrofit create() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder().baseUrl("http://fanyi.youdao.com/").addConverterFactory(GsonConverterFactory.create()).build();
        }
        return retrofit;
    }
 final RequestImpl request = retrofit.create(RequestImpl.class);
        Call<Translation> call = request.getCall();
        call.enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                if (response != null && response.body() != null) {
                    System.out.println("连接成功"+response.body().toString());
                    Log.e("Retrofit","连接成功"+response.body().toString());
                }
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                System.out.println("连接失败");
                Log.e("Retrofit","连接失败");
            }
        });    

源码分析

1、创建retrofit实例

步骤1

此处采用了一个建造者模式

public Builder() {
	this(Platform.get());
}
--------------
//1.内部优先获取一个合适的平台适配 
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) {
    }
    try {
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
  ----------------------------------
  // 2.通过构造函数去配置retrofit的变量 (优先去添加一个默认的数据转换工厂到数据转换工厂适配列表中)
    public static final class Builder {
    // retrofit支持的平台(暂时不太理解)
    private Platform platform;
    //网络请求的工厂 作用是生产网络请求器(call) 默认是的okhttp
    private okhttp3.Call.Factory callFactory;
    //网络请求的url地址
    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());
    }

步骤2

    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      //把URL参数分割成几个路径碎片
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      // 检测最后一个碎片来检查URL参数是不是以"/"结尾
      // 不是就抛出异常	
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

步骤3

addConverterFactory(GsonConverterFactory.create())
先看GsonConverterFactory.create() 此处采用的是抽象工厂模式,(相关的设计模式还有简单工厂模式、工厂方法模式)

//此处是将该数据转换工厂添加的到数据转换工厂集合中去
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

步骤4

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //如果没有手动设置网络请求工厂,默认会提供okhttp进行网络请求
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //如果此处没有提供回调方法执行器,则提供默认使用的platform检测环境时默认的callbackExecutor
     //如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.
      //该手动配置的网络请求适配器工厂添加到网络请求适配器工厂集合中
      //请求适配器工厂集合存储顺序:自定义1适配工厂、自定义2适配工厂.....
      //最后添加一个默认适配器工厂
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      
      // Make a defensive copy of the converters.
      //数据转换工厂集合 之前初始化的时候添加了一个默认数据转换器工厂( BuiltInConverters)
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      // 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

第一阶段小结

Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例

2.创建一个网络请求接口以及实例

<-- 步骤1:定义接收网络数据的类 -->
<-- JavaBean.java -->
public class JavaBean {
  .. // 这里就不介绍了
  }

<-- 步骤2:定义网络请求的接口类 -->
<-- AccessApi.java -->
public interface AccessApi {
    // 注解GET:采用Get方法发送网络请求
    // Retrofit把网络请求的URL分成了2部分:1部分baseurl放在创建Retrofit对象时设置;另一部分在网络请求接口设置(即这里)
    // 如果接口里的URL是一个完整的网址,那么放在创建Retrofit对象时设置的部分可以不设置
    @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
	// 接受网络请求数据的方法
    Call<JavaBean> getCall();
    // 返回类型为Call<*>,*是解析得到的数据类型,即JavaBean
}

创建接口实例

AccessApi NetService = retrofit.create(AccessApi.class);

源码分析

public <T> T create(final Class<T> service) {
    //首先该class是一个接口,其次该接口不能继承其他接口
    Utils.validateServiceInterface(service);
    //是否要提前验证该class里面的方法,并进行解析配置到ServiceMethod对象
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //动态代理模式 即通过动态代理模式创建网络请求接口实例
    //service.getClassLoader(),      // 动态生成接口的实现类 
    // new Class<?>[] { service },    // 动态创建实例
    // new 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, 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);
            }
            
            //核心方法
            //核心方法1 读取网络请求接口中的方法,并根据前面配置好的属性去配置ServiceMethod对象
            ServiceMethod serviceMethod = loadServiceMethod(method); 
            //核心方法2
            //根据配置好的ServiceMethod 去创建okhttCall对象
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); 
            //核心方法3 
            // 根据okHttpCall返回Call
            return serviceMethod.callAdapter.adapt(okHttpCall); 
          }
        });
  }

核心方法1

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    //设置线程同步锁
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      //先判断缓存
      if (result == null) {
      //不存在则去创建对象的ServiceMethod 并放到缓存中
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
  
  ---------------------------
  
  //new ServiceMethod.Builder(this, method).build();分析
  //ServiceMethod包含的成员变量
  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; //网络请求的http请求头 键值对  
  private final MediaType contentType;   // 网络请求的http报文body的类型 
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  // 方法参数处理器
  // 作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
  private final ParameterHandler<?>[] parameterHandlers;
  
  -----------------------------
  public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;

      // 获取网络请求接口方法里的注释
      this.methodAnnotations = method.getAnnotations();
      // 获取网络请求接口方法里的参数类型		
      this.parameterTypes = method.getGenericParameterTypes();	
      //获取网络请求接口方法里的注解内容	
      this.parameterAnnotationsArray = method.getParameterAnnotations();	
    }
    
 ------------------------
 // 作用:控制ServiceMethod对象的生成流程

 public ServiceMethod build() {

      callAdapter = createCallAdapter();	
      // 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器  -->关注点1
     
      responseType = callAdapter.responseType();	
     // 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
     
      responseConverter = createResponseConverter();	
      // 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器  -->关注点3
      // 构造 HTTP 请求时,我们传递的参数都是String
      // Retrofit 类提供 converter把传递的参数都转化为 String 
      // 其余类型的参数都利用 Converter.Factory 的stringConverter 进行转换
      // @Body 和 @Part 类型的参数利用Converter.Factory 提供的 requestBodyConverter 进行转换
      // 这三种 converter 都是通过“询问”工厂列表进行提供,而工厂列表我们可以在构造 Retrofit 对象时进行添加。
      
       
       for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      // 解析网络请求接口中方法的注解
      // 主要是解析获取Http请求的方法
     // 注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded
     // 处理主要是调用方法 parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值
      
     int parameterCount = parameterAnnotationsArray.length;
     // 获取当前方法的参数数量
      
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
	    // 为方法中的每个参数创建一个ParameterHandler<?>对象并解析每个参数使用的注解类型
        // 该对象的创建过程就是对方法参数中注解进行解析
        // 这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url 
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      } 
      return new ServiceMethod<>(this);

<-- 关注点1:createCallAdapter() -->
 private CallAdapter<?> createCallAdapter() {

      // 获取网络请求接口里方法的返回值类型
      Type returnType = method.getGenericReturnType();		

      // 获取网络请求接口接口里的注解
      // 此处使用的是@Get
      Annotation[] annotations = method.getAnnotations();		
      try {

      return retrofit.callAdapter(returnType, annotations);	
      // 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
      // 下面会详细说明retrofit.callAdapter() -- >关注点2
      }
...


<-- 关注点2:retrofit.callAdapter()  -->
 public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

 public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {

    // 创建 CallAdapter 如下
    // 遍历 CallAdapter.Factory 集合寻找合适的工厂(该工厂集合在第一步构造 Retrofit 对象时进行添加(第一步时已经说明))
    // 如果最终没有工厂提供需要的 CallAdapter,将抛出异常
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);		
      if (adapter != null) {
        return adapter;
      }
    }


<--   关注点3:createResponseConverter() -->

 private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
	
        // responseConverter 还是由 Retrofit 类提供  -->关注点4
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { 
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }

<--   关注点4:responseBodyConverter() -->
  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

 public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {

       // 获取Converter 过程:(和获取 callAdapter 基本一致)
         Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);	
       // 遍历 Converter.Factory 集合并寻找合适的工厂(该工厂集合在构造 Retrofit 对象时进行添加(第一步时已经说明))
       // 由于构造Retroifit采用的是Gson解析方式,所以取出的是GsonResponseBodyConverter
       // Retrofit - Converters 还提供了 JSON,XML,ProtoBuf 等类型数据的转换功能。
       // 继续看responseBodyConverter() -->关注点5	
    }


<--   关注点5:responseBodyConverter() -->
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, 
    Annotation[] annotations, Retrofit retrofit) {

  
  TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  // 根据目标类型,利用 Gson#getAdapter 获取相应的 adapter
  return new GsonResponseBodyConverter<>(gson, adapter);
}

// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override 
   public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}

核心方法2 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

<--OkHttpCall类 -->
public class OkHttpCall {
    private final ServiceMethod<T> serviceMethod; // 含有所有网络请求参数信息的对象  
    private final Object[] args; // 网络请求接口的参数 
    private okhttp3.Call rawCall; //实际进行网络访问的类  
    private Throwable creationFailure; //几个状态标志位  
    private boolean executed;  
    private volatile boolean canceled;  
  
<--OkHttpCall构造函数 -->
  public OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {  
    // 传入了配置好的ServiceMethod对象和输入的请求参数
    this.serviceMethod = serviceMethod;  
    this.args = args;  
}  

核心方法3 return serviceMethod.callAdapter.adapt(okHttpCall);

//此处使用的是装饰器模式 (不是静态代理模式 2者是有区别的 因为这边传入的是call 该类继承的也是call)
 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;
        }

        public void enqueue(final Callback<T> callback) {
            if (callback == null) {
                throw new NullPointerException("callback == null");
            } else {
            //这个地方是异步操作 应该是在子线程里面执行的
                this.delegate.enqueue(new Callback<T>() {
                    public void onResponse(Call<T> call, final Response<T> response) {
                    //callbackExecutor之前讲过 主要是将数据通过回调到主线程进行执行的
                        ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                            public void run() {
                                if (ExecutorCallbackCall.this.delegate.isCanceled()) {
                                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                                } else {
                                    callback.onResponse(ExecutorCallbackCall.this, response);
                                }

                            }
                        });
                    }

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

通过网络接口请求实例去调用相关请求方法

Call call = NetService.getCall();
OkHttpCall类是OkHttp的包装类
创建了OkHttpCall类型的Call对象还不能发送网络请求,需要创建Request对象才能发送网络请求

执行网络请求 同步异步

异步

call.enqueue(new Callback<Translation>() {
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                if (response != null && response.body() != null) {
                    System.out.println("连接成功"+response.body().toString());
                    Log.e("Retrofit","连接成功"+response.body().toString());
                }
            }

            @Override
            public void onFailure(Call<Translation> call, Throwable t) {
                System.out.println("连接失败");
                Log.e("Retrofit","连接失败");
            }
        });
-------------------------
static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      //delegate 是之前的包装类OkHttpCall
      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是回调执行器 当内部执行完okhttpcall的onresponse后回调到主线程
          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);
            }
          });
        }
      });
    }

delegate.enqueue(xxx) delegate是okhttpCall

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("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 {
        //获取的是okhttp3.Call
          call = rawCall = createRawCall();//步骤1
        } catch (Throwable 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)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

//步骤1  获取的是okhttp3.Call
  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;
  }

同步略掉

总结

至此,从代码层面分析完了retrofit的请求全流程,基本上都是对okhttp的封装,最终的实现还是交给okhttp实现,那为什么不直接使用okhttp呢? 参考1
参考2

延伸

retrofit相对于okhttp的好处在哪?retrofit的优缺点 okhttp的优缺点

1.okhttp的回调是运行在子线程里面的,所以需要自己手动通过hanlder回调到主线程 2.retrofit针对网络请求不同请求方法如post get 等等 都需要添加相应的基类,导致类过多 是比较耗性能的 3.retrofit毕竟只是针对okhttp的封装 如果网络底层换成volley呢,那相应所有网络请求都需要更改,但是retrofit可以保留现有逻辑代码,只需要底层更改一个网络请求库即可 参考1
参考2
参考3

Volley的弊端

针对大文件下载 volley是通过byte的方式导致下载大文件性能非常差,而okhttp是通过流的方式

retrofit里面涉及到的知识点学习

注解(运行时 编译时)、反射、动态代理、构建者模式 hander原理(后续都需要把对应连接补上)(动态代理跟注解的关系)

retrofit面试考点 流程(后续补充)

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们