Retrofit源码解析

本文详细剖析了Retrofit的工作原理,从Java接口定义、构建Retrofit对象到生成接口对象和执行网络请求,深入探讨了Retrofit的核心组件,如ServiceMethod、CallAdapter和Converter。通过分析,展示了Retrofit如何利用动态代理、注解解析和平台适配实现类型安全的HTTP客户端功能。
摘要由CSDN通过智能技术生成


以Retrofit2.4为例。

概述

Retrofit适用于Android和Java的类型安全的HTTP客户端。一个RESTful的基于OKHttp的Http网络框架。简单网络请求,提高开发效率。

使用如下

  1. 定义Java接口
public interface GitHubService {
   
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
  1. 构建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
  1. 生成Java接口对象
GitHubService service = retrofit.create(GitHubService.class);
  1. 调用对象的方法获取对应的Call
Call<List<Repo>> repos = service.listRepos("octocat");
  1. 也就是调用Callexecute方法进行同步网络请求,或者调用enqueue进行异步的网路请求。

接下来我们会根据一一分析这5个步骤。基于Retrofit2.4.0分析。

Java接口定义

由于Retrofit使用的动态代理进行生成接口对象的,我们的网络请求的接口必须是Java接口。

Retrofit定义了许多的注解。定义网络请求的接口就是通过这些注解来完成的。

屏幕快照 2018-12-17 上午11.05.19

注解会保留到运行时,因为Retrofit需要根据这些注解去解析运行时的参数。

比如GET注解

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
   
  String value() default "";
}

GET方法上的注解,注解保留到运行时。

构建Retrofit对象

创建过程

使用了Builder模式来创建Retrofit对象。Retrofit.Builder拥有很多创建Retrofit的配置项,通过这些配置项来创建Retrofit对象。每个配置项的方法返回Builder对象,用于.来进行配置的连接,最后通过build方法创建Retrofit

比如配置baseUrl

public static final class Builder {
   
    public Builder baseUrl(String baseUrl) {
   
      checkNotNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
    }

    public Builder baseUrl(HttpUrl baseUrl) {
   
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
   
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }
}

检测baseUrl是否为null,调用重载的baseUrl方法。baseUrl(HttpUrl baseUrl)中检测baseUrl是否为null,并且检测url是否合法,最后赋值给Builder对象的baseUrl。最后返回this

build方法:

public static final class Builder {
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
	  ......
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
}

通过此方法返回Retrofit对象。

这里先不进行配置项相关的说明,后面碰到会说明。

生成Java接口对象

Retrofit创建接口对象

获取接口对象时,是通过Retrofitcreate方法。

public final class Retrofit {
   
    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);
            		}
            		ServiceMethod<Object, Object> serviceMethod =
                			(ServiceMethod<Object, Object>) loadServiceMethod(method);
            		OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            		return serviceMethod.adapt(okHttpCall);
          		}
        	});
  	}
}

首先调用Utils.validateServiceInterface方法验证service

final class Utils {
    static <T> void validateServiceInterface(Class<T> service) {
    	if (!service.isInterface()) {
	    	throw new IllegalArgumentException("API declarations must be interfaces.");
    	}
    	if (service.getInterfaces().length > 0) {
      		throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    	}
  	}
}

此方法验证service是不是Java接口,并且验证接口是否继承了其他接口。

接着分析Retrofitcreate的方法。通过变量validateEagerly来判断是否调用eagerlyValidateMethods方法,validateEagerly表示是否调用create方法时急切的验证接口中的方法的配置,默认是false

接着是创建一个InvocationHandler匿名内部类对象,调用Proxy.newProxyInstance的方法来创建一个Java接口对象。这里使用了Java的动态代理的知识。一旦调用Java接口中的方法就会调用到InvocationHandler中的invoke方法。

总结:

Retrofit的create方法有两个功能,一是验证接口,一个是通过Proxy.newProxyInstance方法生成一个动态代理的Java接口对象。

调用对象的方法获取Call

通过接口获取Call

调用对象的方法会调用到InvocationHandler匿名对象的invoke方法。

Call<List<Repo>> repos = service.listRepos("octocat");

我们来分析一下InvocationHandler匿名内部对象的invoke方法。

public final class Retrofit {
   
    public <T> T create(final Class<T> 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 (method.getDeclaringClass() == Object.class) {
   
              			return method.invoke(this, args);
            		}
            		if (platform.isDefaultMethod(method)) {
   
              			return platform.invokeDefaultMethod(method, service, proxy, args);
            		}
            		ServiceMethod<Object, Object> serviceMethod =
                			(ServiceMethod<Object, Object>) loadServiceMethod(method);
            		OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            		return serviceMethod.adapt(okHttpCall);
          	}
        });
  	}
}

invoke有三个参数,proxy是调用者对象,method调用的方法,args调用方法的参数。

首先调用methodgetDeclaringClass获取声明类是不是Object

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值