Retrofit2 源码分析

Retrofit 提供了一种REST格式的网络请求,对OKhttp进行了更近一层的封装,最近阅读了一下源码,Retrofit本身代码量不多,相当紧凑,值得学习


Retrofit最核心的类为Retrofit.java和ServiceMethod.java这两个类,其中Retrofit.Builder这个内部类负责Retrofit模块的初始化工作。

在设计项目的时候在需要Retrofit的时候通过改变这个Builder来创建不同的Retrofit实例.

来看看这个Builder最后构建Retrofit的时候初始化了哪些

/**
   * Create the {@link Retrofit} instance using the configured values.
   * <p>
   * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
   * OkHttpClient} will be created and used.
   */
  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);
  }
}
可以看到初始化了OkhttpClient,默认的adapter,还有baseUrl(基础的连接地址),还有转换的工厂列表,适配器工厂列表,validateEagerly这个变量是是否先缓存Service中的方法

接下来看这个函数

// Single-interface proxy creation guarded by parameter safety.
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 serviceMethod = loadServiceMethod(method);
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}
这个函数我们在创建具体的服务API接口的时候会调用

Utils.validateServiceInterface(service);
这句话判断这个Service是否是接口
  if (validateEagerly) {
    eagerlyValidateMethods(service);
  }
这个是缓存Service的Method,可以具体看下:

private void eagerlyValidateMethods(Class<?> service) {
  Platform platform = Platform.get();
  for (Method method : service.getDeclaredMethods()) {
    if (!platform.isDefaultMethod(method)) {
      loadServiceMethod(method);
    }
  }
}
这个地方可以看出这个方法将Service中的所有API接口都先load好,做一个缓存的作用,这样在真正调用方法的时候就可以直接从缓存中拿,提升了效率。

接下来就是用的反射了,Proxy这个类是属于Java Reflect包下面的,用反射的方法来构造接口类Service的实例,

当我们来调用Service中的某个具体接口的时候,会回调

InvocationHandler中的invoke方法。来看看这里具体做了哪些操作:

if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
这里是来判断这个方法是否是Object这个基类的方法,如果是则直接返回Object的方法。这里可以看出代码逻辑的严谨性是值得我们来学习的。

if (platform.isDefaultMethod(method)) {
  return platform.invokeDefaultMethod(method, service, proxy, args);
}
这里判断条件始终为false,所以不会走。保留这个逻辑应该是想针对某些平台的默认方法来做的。

接着

ServiceMethod serviceMethod = loadServiceMethod(method);
这就是最核心的方法了。用来加载API的具体方法

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
初始化了一个OkhttpCall来处理网络接连,这里Retrofit对Okhttp请求进行了一次封装

最后调用

serviceMethod.callAdapter.adapt(okHttpCall)
来通过各种adapter来处理请求,并且返回相应格式的数据。


下面我们来看下loadServiceMethod这个方法

ServiceMethod loadServiceMethod(Method method) {
  ServiceMethod result;
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      result = new ServiceMethod.Builder(this, method).build();
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
这里做了一个缓存,最核心的是这句:

result = new ServiceMethod.Builder(this, method).build();
来看看ServiceMethod做了些什么

首先是构建了一个Builder:

public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
这个Builder其实主要的就是获取方法的注解,参数类型以及参数上的注解,做了一些初始化的工作

来看看Builder.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 = createCallAdapter();
这句话具体干了一件事:根据Method的返回值来获取Adapter列表中对应的Adapter。

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?");
}
这里是做一个保护,Retrofit是不允许直接返回Response的。

responseConverter = createResponseConverter();
这句话来获取返回数据的转换实例。

接下来的代码比较简单,根据注解来解析对应的参数,最后返回ServiceMethod实例。

整个代码逻辑十分清晰,对于具体的Adapter和Converter,Retrofit做了拆分,剥离主项目,想必是想让Retrofit更加聚焦于框架的设计,

而具体的业务类似返回数据解析和返回数据处理都用接口的方式来处理,使得整个项目架构清晰。

这种框架的思想是值得我们学习的,看看代码其实逻辑并不复杂。但是如果我们来写可能就会把Adapter和Converer写到框架中去了。

所以我们在平时写代码的时候更多的需要去来抽象一些模型,使得我们在框架设计上有更多的积累。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
retrofit2是一个用于Android和Java平台的类型安全的HTTP客户端库,它可以用来进行网络请求和数据交互。在retrofit2中,可以使用SSE(Server-Sent Events)来进行服务器推送的实现。 SSE是一种在客户端和服务器之间单向实时通信的技术,它允许服务器发送事件数据到客户端,而客户端则可以监听这些事件并做出相应的处理。在retrofit2中,可以通过定义一个接口来实现SSE的处理,如下所示: ```java public interface SSEService { @GET("/events") Call<ResponseBody> getEvents(); } ``` 在这个例子中,我们定义了一个SSEService接口,其中包含一个用于获取事件数据的GET请求。当调用这个接口时,retrofit2会使用OkHttp来建立连接并监听服务器发送的事件数据。 另外,为了处理服务器发送的事件数据,可以使用retrofit2的Call对象和Callback来实现。例如: ```java SSEService service = retrofit.create(SSEService.class); Call<ResponseBody> call = service.getEvents(); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { // 处理服务器发送的事件数据 } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { // 处理请求失败的情况 } }); ``` 通过使用retrofit2的SSE功能,可以很方便地实现客户端和服务器之间的实时事件推送和处理。这使得在Android和Java应用中,可以更加灵活和高效地处理服务器推送的事件数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值