retrofit2.5.0 source code analysis

Brief introduction

Retrofit is the more popular network framework, it is restful style request mode, the interface will request the use of dynamic proxy approach will get the method name, notes, annotation method parameters, method values ​​translated into http request, to the inside of the package as okhttp underlying network request frame. In addition there is a strong scalable, and return the results support a variety of format conversion, and support for the rxjava.

gradle quote

implementation 'com.squareup.retrofit2:retrofit:2.5.0'
//rxjava
api 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
//数据转换
api 'com.squareup.retrofit2:converter-gson:2.5.0'
//过滤器
api 'com.squareup.okhttp3:logging-interceptor:3.8.0'

github address https://github.com/square/retrofit

use

Official instructions http://square.github.io/retrofit/

First create an interface api

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

Obtain dynamic proxy object

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

 GitHubService gitHubService =  retrofit.create(GitHubService.class);

Creating a Call object

   Call<Repo> call = gitHubService.listRepos("");

Performing asynchronous network requests

call.enqueue(new Callback<Repo>() {
       @Override
       public void onResponse(Call<Repo> call, Response<Repo> response) {

       }

       @Override
       public void onFailure(Call<Repo> call, Throwable t) {

       }
   });

problem

Source resolve

 Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

First retrofit by a Builder mode, create a retrofit instance.

 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.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(
      1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // 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);
  converterFactories.addAll(platform.defaultConverterFactories());

  return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

Attribute verification method by a build and initialize some variables.

 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();
      private final Object[] emptyArgs = new Object[0];

      @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);
        }
        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
      }
    });
}

Then create an interface instance creat, creat mainly by Proxy.newProxyInstance create a dynamic proxy method. In the method of the invoke method newProxyInstance method you can get the name of the interface; key value annotation annotation types of methods, and interface methods, and the value of the value of the annotation.

 GitHubService gitHubService=(GitHubService) Proxy.newProxyInstance(GitHubService.class.getClassLoader(),
            new Class[]{GitHubService.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("方法名"+method.getName());
                    GET get = method.getAnnotation(GET.class);
                    System.out.println("方法的注解值"+get.value());
                    Annotation[] annotations = method.getAnnotations();
                    for (int i = 0; i <annotations.length ; i++) {
                        System.out.println("方法参数的注解"+Arrays.toString(annotations));
                    }
                   System.out.println("方法的参数值"+Arrays.toString(args));
                    return null;
                }
            });
    gitHubService.listRepos("111");

Some information related to the acquisition method through a proxy

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;
}

loadServiceMethod ServiceMethod method returns the object. If there is a cache to fetch from the cache, if there is no direct release to create a map. ServiceMethod = ServiceMethod.parseAnnotations (this, method) acquired by the result.

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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}



   static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
  Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
  throw methodError(method, "'"
      + Utils.getRawType(responseType).getName()
      + "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
  throw methodError(method, "HEAD method must use Void as response type.");
}

Converter<ResponseBody, ResponseT> responseConverter =
    createResponseConverter(retrofit, method, responseType);

okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}

ServiceMethod is an abstract class, which is called a subclass method parseAnnotations HttpServiceMethod directly new HttpServiceMethod objects in the process.

 private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
  CallAdapter<ResponseT, ReturnT> callAdapter,
  Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.callAdapter = callAdapter;
this.responseConverter = responseConverter;
}

Properties and methods HttpServiceMethod class.

return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

Back to creat method, the last call that invoke method.

@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
    new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

Invoke specific implementation, the method will return a Call object, allAdapter.adapt () method is to convert the objects into OkHttpCall Call object can be used on other platforms, such as: RxJava. Here returns OkHttpCall object class is defined Retrofit, it is the encapsulation of Okhttp Call object.

OkHttpCall(RequestFactory requestFactory, Object[] args,
  okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
this.requestFactory = requestFactory;
this.args = args;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}

……
……

 @Override public synchronized Request request() {
okhttp3.Call call = rawCall;
if (call != null) {
  return call.request();
}
if (creationFailure != null) {
  if (creationFailure instanceof IOException) {
    throw new RuntimeException("Unable to create request.", creationFailure);
  } else if (creationFailure instanceof RuntimeException) {
    throw (RuntimeException) creationFailure;
  } else {
    throw (Error) creationFailure;
  }
}
try {
  return (rawCall = createRawCall()).request();
} catch (RuntimeException | Error e) {
  throwIfFatal(e); // Do not assign a fatal error to creationFailure.
  creationFailure = e;
  throw e;
} catch (IOException e) {
  creationFailure = e;
  throw new RuntimeException("Unable to create request.", e);
}
}

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

These are part of the code OkHttpCall objects, in fact, mainly to internal network synchronization object calls okhttp3 call or asynchronous request and the like.

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;
}

Okhttp3.Call objects created by the create method requestFactory.

final class RequestFactory {

  ………………

 Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
  }

………………

okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

int argumentCount = args.length;
if (argumentCount != handlers.length) {
  throw new IllegalArgumentException("Argument count (" + argumentCount
      + ") doesn't match expected count (" + handlers.length + ")");
}

RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
    headers, contentType, hasBody, isFormEncoded, isMultipart);

List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
  argumentList.add(args[p]);
  handlers[p].apply(requestBuilder, args[p]);
}

return requestBuilder.get()
    .tag(Invocation.class, new Invocation(method, argumentList))
    .build();
}
}

In RequestFactory class it can be seen that the method according to the Request object to create args ParameterHandler analytical parameters and parameter values ​​passed.

to sum up

Call Retrofit.creat method to create interface instance. Internal dynamic proxies, ServiceMethod call invoke methods, ServiceMethod is an abstract class, it is actually a subclass of HttpServiceMethod
calls. HttpServiceMethod is encapsulation of request method, mainly requestFactory, callFactory, callAdapter, responseConverter member variable.

Reproduced in: https: //www.jianshu.com/p/4d911c76e320

Guess you like

Origin blog.csdn.net/weixin_34376562/article/details/91225609