Retrofit 2.0 Source Code Analysis

Retrofit 2.0 describes an HTTP request in the form of annotations, abstracts the HTTP request into a Java interface, and then uses Java dynamic proxy to "translate" the annotation of this excuse into an HTTP request, and then executes the HTTP request.
Examples are given to illustrate:
Request an api: https://api.github.com/repos/{owner}/{repo}/contributors
View contributors for a repo on github.
First you need to build an interface like this:
public interface GitHub {
	
	@GET("/repos/{owner}/{repo}/contributors")
	Call<List<Contributor>> contributors(@Path("owner")String owner,@Path("repo")String repo);
}
Then create a Retrofit
public static final String BASIC_URL="https://api.github.com";

Retrofit mRetrofit =new Retrofit.Builder().baseUrl(BASIC_URL).addConverterFactory
(GsonConverterFactory.create()).build();
Create a GitHub
GitHub gitHub =mRetrofit.create(GitHub.class);
Call<List<Contributor>> call =gitHub.contributors("owner","repo");
Final callback to get data
call.enqueue(new Callback<List<Contributor>>(){
	@Override
	public void onResponse(Response<List<Contributor>>respone){
		for(Contributor controbutor: respone.body){


		}
	}


	@Override
	public void onFailure(Throwable t){


	}
});

The important thing about the create method is that it returns a dynamic proxy object. (Java dynamic proxy is Java development that gives developers the possibility to insert the code you want to execute before you call a method of a class

For example, before you perform an operation, you have to decide whether the user is logged in or whether there is so much money in the person's account before you pay for it. In such a simple sentence, I believe that a person who does not understand technology can also explain what Java dynamic proxy is.)

// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
Source code:
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);
        }
        return loadMethodHandler(method).invoke(args);
      }
    });

Generating an HTTP request is this sentence: Call < List < Contributor > call = github. contributors ("square", "retrofit");
github is a dynamic proxy object, not a real Githb interface implements object, when the github object calls the contributors method

Retrofit actually executes the InvocationHandler object of the dynamic proxy, and eventually creates a MethodHandler object (the Github interface translates into an HTTP request, that is, a MethodHandler object).

This object contains four parts

static MethodHandler<?> create(Retrofit retrofit, Method method) {
    CallAdapter<Object> callAdapter = (CallAdapter<Object>) createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    Converter<ResponseBody, Object> responseConverter =
        (Converter<ResponseBody, Object>) createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);


    return new MethodHandler<>(retrofit.client(), requestFactory, callAdapter, responseConverter);
}
1. OkHttpClient: Retrofit default generated tool for sending network requests
2. RequestFactory: Similar to Request in Volley, it contains Url, Header information of HTTP requests, MediaType, Method and RequestAction array. It is generated by RequestFactoryParser.parse(method, responseType, retrofit). Its main function is to parse all data of the whole Http request, get all information of the whole Http request, and stitch Url through @Path and @Query annotations.
3. CallAdapter: The type of data returned by HTTP requests
private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
  Type returnType = method.getGenericReturnType();
  if (Utils.hasUnresolvableType(returnType)) {
    throw Utils.methodError(method,
      "Method return type must not include a type variable or wildcard: %s", returnType);
  }
  if (returnType == void.class) {
    throw Utils.methodError(method, "Service methods cannot return void.");
  }
  Annotation[] annotations = method.getAnnotations();
  try {
    return retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
  }
}
4. Converter: Data converter, HTTP returned data parsed into Java objects
 private static Converter<ResponseBody, ?> createResponseConverter(Method method,
  Retrofit retrofit, Type responseType) {
  Annotation[] annotations = method.getAnnotations();
  try {
    return retrofit.responseBodyConverter(responseType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
  }
}

The purpose of creating these four objects is to execute the following code
Object invoke(Object... args) {
  return callAdapter.adapt(new OkHttpCall<>(client, requestFactory, responseConverter, args));
}
This is the Call object returned by github.contributors("square", "retrofit")
Finally, you can send an Http request by calling the execute() or enqueue (Callback < T > callback) method of the Call object.

Retrofit interface
1. This interface is the retrofit request data return interface, there are only two methods.
void onResponse(Response<T> response);
void onFailure(Throwable t);
2.Converter<F, T>
The main function of this interface is to parse HTTP returned data into Java objects, mainly by Xml, Gson, protobuf and so on. You can add the Converter implementation you need to use when creating Retrofit objects (see the code for creating Retrofit objects above).
3.Call<T>
The main function of this interface is to send an HTTP request. The default implementation of Retrofit is OkHttpCall<T>. You can implement your own Call class according to the actual situation. This design is very similar to Volley's HTTP Stack interface design. Subclass can implement HTTP request tool based on HttpClient or HttpUrlConnection. This design is very plug-in and flexible.
4.CallAdapter<T>

As mentioned above, there is only one responseType attribute in CallAdapter, and another < R > T adapt (Call < R > call) method. There is only one implementation class for this interface, DefaultCallAdapter. The main function of this method is to convert the Call object into another object, which may be designed to support RxJava.

===========================================>

Article reprinted: http://bxbxbai.github.io/2015/12/13/retrofit2/

Keywords: Retrofit github Java network

Added by harkonenn on Sun, 30 Jun 2019 22:31:49 +0300