Retrofit源码解析

栏目: Java · 发布时间: 5年前

内容简介:retrofit是一种类型安全的HTTP客户端。所谓的类型安全,就是说在运行时不会报类型错误,它会在编译期检查。 要分析它的源码当然是从使用开始说起。在之前的例子中通过Retrofit.create()方法来生成网络请求对象,利用这个对象进行相关的同步或者异步请求。所以从这里开始。先关方法的含义已经写到注释里了,因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法从上面可以看出无非就是之前加载过的话就从缓存中取,没加载过的话就的重新构建并且加入到

retrofit是一种类型安全的HTTP客户端。所谓的类型安全,就是说在运行时不会报类型错误,它会在编译期检查。 要分析它的源码当然是从使用开始说起。在之前的例子中通过Retrofit.create()方法来生成网络请求对象,利用这个对象进行相关的同步或者异步请求。所以从这里开始。

public <T> T create(final Class<T> service) {
    //验证是否为接口而且是不继承其他接口的接口
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }

    //核心就是动态代理,就是创建一个对象,它会代理service(接口)中的每个方法,
    //然后把接口中的每个方法通过serviceMethod.callAdapter.adapt(okHttpCall);代替返回相应的结果
    //参数一:类加载器,参数二:动态代理代理的是哪些类,参数三
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
                //Anddroid的还是 Java 8、Java7等
                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.
                    //如果是Object类自有的方法就直接执行
                    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);
                    //call就做了两件事
                    //一:生成一个真正的OKHTTP的call并且加入请求队列
                    //二:对返回结果利用之前定义的converter转换后返回给callback
                    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    //之所以会用adapter的adapt方法主要是为了线程切换(rxjava的转换),这里是把结果切回主线程
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

复制代码

先关方法的含义已经写到注释里了,因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法 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;
}
复制代码

从上面可以看出无非就是之前加载过的话就从缓存中取,没加载过的话就的重新构建并且加入到缓存中。找到方法之后则很自然的要执行这个方法,那就得是OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);通过这步把要执行的方法及参数保存到了OKHTTP的call中,当执行enqueque的时候则真正的用得到的方法和参数请求网络。 在基本使用中,构造完网络请求对象之后,就用这个对象进行实际的网络请求,比如异步的enquue。

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

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

    private void callFailure(Throwable e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    private void callSuccess(Response<T> response) {
      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}
复制代码

上面代码中最重要的则是 createRawCall() ,也就是创建OKHTTP的call,然后利用这个call调用OKHTTP的enqueque来进行真正的网络请求,同时将返回值返回到callback中。 到这里已经可以拿到网络通信结果了当然是通过 parseResponse(rawResponse) 转换的最终结果,而这个转换则是通过初始化时 addConverterFactory 添加的转换器,为什么不直接返回这个okHttpCall而是还要进行下一步 return serviceMethod.callAdapter.adapt(okHttpCall); 那就得看一下OKHTTP的enqueque做了什么

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

复制代码

OKHTTP的实现类中的enqueue调用了 client.dispatcher().enqueue(),继续看这个enqueque

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}
复制代码

从这个理可以看出来如果当前发送请求的数量大于 maxRequests (当前源码数量为64),加入队列待执行,如果没到则执行,而执行的代码可以清楚的看到使用executorService().execute(call)。说明在后台线程池中进行的请求和返回。那么到这里就大致的可以推断出return adatp的作用了,那就是 线程切换 。 直接跟进去发现adapt方法是在接口类中,那么我们直接找它的实现类看看,一共有两个即 ExecutorCallAdapterFactoryDefaultCallAdapterFactory ,然后再看这两个类在那儿用的,发现是在下面这个方法中调用的

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor != null) {
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
  return DefaultCallAdapterFactory.INSTANCE;
}
复制代码

而这个方法有又是retrofit的build()方法中,也就是刚才说的初始化话过程中已经做了

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);
  }
}
复制代码

而在这个方法中我们看到需要向方法中传一个callbackExecutor,而这个executor从字面看就是与平台相关的,那么Android平台的是什么样子呢

static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    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);
    }
  }
}
复制代码

从handler.post我们一下子就豁然开朗了。 大框架已经已经说完了,那么那些注解什么时候用的呢,那就得从构造方法和参数入手了,仔细看一下

ServiceMethod.Builder<>(this, method).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();

  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);
}
复制代码

从上面的源码可以看出首先创建了最后一步需要的callAdapter,然后创建ResponseConverter,也就是通常的将结果转化为Gson等的转换器。然后解析方法注解parseMethodAnnotation(annotation);、解析参数注解parseParameter(p, parameterType, parameterAnnotations)。最后生成的请求和返回所需要的全部参数如下

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;
}
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Redis开发与运维

Redis开发与运维

付磊、张益军 / 机械工业出版社 / 2017-3-1 / 89.00

本书全面讲解Redis基本功能及其应用,并结合线上开发与运维监控中的实际使用案例,深入分析并总结了实际开发运维中遇到的“陷阱”,以及背后的原因, 包含大规模集群开发与管理的场景、应用案例与开发技巧,为高效开发运维提供了大量实际经验和建议。本书不要求读者有任何Redis使用经验,对入门与进阶DevOps的开发者提供有价值的帮助。主要内容包括:Redis的安装配置、API、各种高效功能、客户端、持久化......一起来看看 《Redis开发与运维》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具