站在巨人的肩膀上 -- Retrofit源码解析

Posted 巨头之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了站在巨人的肩膀上 -- Retrofit源码解析相关的知识,希望对你有一定的参考价值。

前言

每次看完Retrofit的源码,下次再看时很容易就忘记了,Retrofit的源码中用了大量的设计模式,刚开始看时感觉就是代码中调来调去。。。绕来绕去。。。真的。。。没有点到即止的话~很容易就晕了,所以这次我从使用的API的角度出发,将对Retrofit的解析写成笔记.


Retrofit源码基于版本2.4.0

首先看下Retrofit的基本使用:

  • 1.首先创建用于网络请求的API接口:

    
    	public interface GitHub 
    	    @GET("/repos/owner/repo/contributors")
    	    Call<List<Contributor>> contributors(
    	        @Path("owner") String owner,
    	        @Path("repo") String repo);
    
    	
    
  • 2.创建用于接收响应实体的类

    
    	public static class Contributor 
    	    public final String login;
    	    public final int contributions;
    	
    	    public Contributor(String login, int contributions) 
    	      this.login = login;
    	      this.contributions = contributions;
    	    
    	
    
  • 3.创建Retrofit实例并发起请求

    
    	public static void main(String... args) throws IOException 
        	Retrofit retrofit = new Retrofit.Builder()
    	       .baseUrl(API_URL)
    	       .addConverterFactory(GsonConverterFactory.create())
    	       .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    	       .build();
    	
    	    GitHub github = retrofit.create(GitHub.class);
    	
    	    Call<List<Contributor>> call = github.contributors("square", "retrofit");
    		//同步请求
    	    List<Contributor> contributors = call.execute().body();
    	    //异步请求
    	    call.enqueue(new Callback<List<Contributor>>() 
    	      @Override
    	      public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) 
    	      
    	      @Override
    	      public void onFailure(Call<List<Contributor>> call, Throwable t) 
    	      
    	    );
    

2.从Retrofit的基本API入手:

a.Retrofit构建过程

  • 1.Retrofit.Builder(): 获取对应平台的Platform实例,这里是获取到android类的实例.

    
    	public final class Retrofit 
    		 public static final class Builder 
    
    			Builder(Platform platform) 
    		      this.platform = platform;
    		    
    		
    		    public Builder() 
    		      //Platform是获取相应的平台,有Android、Java等
    		      this(Platform.get());
    		    
    		
    	
    

    在Android类里主要是维护了MainThreadExecutor类,来将子线程切换到主线程

    
    	//适配平台
    	class Platform 
    		
    		 private static final Platform PLATFORM = findPlatform();
    
    		  static Platform get() 
    		    return PLATFORM;
    		  
    		
    		  //寻找对应的平台
    		  private static Platform findPlatform() 
    		    try 
    		      //通过JVM加载类的方式判断是否是Android平台
    		      Class.forName("android.os.Build");
    		      if (Build.VERSION.SDK_INT != 0) 
    		        return new Android();
    		      
    		     catch (ClassNotFoundException ignored) 
    		    
    		    try 
    		      Class.forName("java.util.Optional");
    		      return new Java8();
    		     catch (ClassNotFoundException ignored) 
    		    
    		    return new Platform();
    		  
    
    	
    
    
    	  //Android平台对应的类
    	  static class Android extends Platform 
    	    //返回可以将子线程切换到主线程的线程池
    	    @Override public Executor defaultCallbackExecutor() 
    	      return new MainThreadExecutor();
    	    
    	
    	    //工厂方法模式,将Executor实例装载进工厂类
    	    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) 
    	      if (callbackExecutor == null) throw new AssertionError();
    	      return new ExecutorCallAdapterFactory(callbackExecutor);
    	    
    	
    	    static class MainThreadExecutor implements Executor 
    	      //Android主线程的Hnadler
    	      private final Handler handler = new Handler(Looper.getMainLooper());
    	
    	      @Override public void execute(Runnable r) 
    	         //将子线程切换到主线程
    	         handler.post(r);
    	      
    	    
    	  
    	
    
  • 2.baseUrl( ): 判断基础的url不能为空,将String类型的url转化成HttpUrl实例

    
    	public final class Retrofit 
    		public static final class Builder 
    
    			public Builder baseUrl(String baseUrl) 
    		      //基础的url不能为空
    		      checkNotNull(baseUrl, "baseUrl == null");
    		      //将String类型的url 转化成 HttpUrl实例
    		      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
    		      if (httpUrl == null) 
    		        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
    		      
    		      return baseUrl(httpUrl);
    		    
    
    			
    	
    

    HttpUrl类用了Build模式来创建

    
    	public final class HttpUrl 
    		public static final class Builder 
    
    			@Nullable
    		    public static HttpUrl parse(String url) 
    				//build模式创建HttpUrl
    		        HttpUrl.Builder builder = new HttpUrl.Builder();
    		        HttpUrl.Builder.ParseResult result = builder.parse((HttpUrl)null, url);
    		        return result == HttpUrl.Builder.ParseResult.SUCCESS ? builder.build() : null;
    		    		
    		
    	
    
    	
    
  • 3.addConverterFactory(): 将数据转换器工厂添加到converterFactories这个存放数据转换器工厂(集合的元素类型为Converter.Factory)的集合中

    
    	 //将数据转换器工厂添加到converterFactories这个存放数据转换器工厂(集合的元素类型为Converter.Factory)的集合中
        // 比如 GsonConverterFactory这个Gson数据转换器
        public Builder addConverterFactory(Converter.Factory factory) 
            converterFactories.add(checkNotNull(factory, "factory == null"));
            return this;
        
    
  • 4.addCallAdapterFactory(): 将网络请求适配器工厂添加到callAdapterFactories这个存放网络请求适配器工厂(集合的元素类型为CallAdapter.Factory)的集合中

    
    	//将网络请求适配器工厂添加到callAdapterFactories这个存放网络请求适配器工厂(集合的元素类型为CallAdapter.Factory)的集合中
        //比如 开发者可添加 RxJavaCallAdapterFactory 这个RX网络请求适配器
        public Builder addCallAdapterFactory(CallAdapter.Factory factory) 
           callAdapterFactories.add(checkNotNull(factory, "factory == null"));
           return this;
        
    
  • 5.build():

    • 检查了OkHttpClient和回调线程池类Executor是否传入值,未传入则创建默认的值,已传入则使用开发者设置的值

    • 往存放数据转换器工厂的集合存入开发者设置的数据转换器工厂(例如GsonConverterFactory)和系统默认的数据转换器工厂(BuiltInConverters)

    • 往存放网络请求适配器工厂的集合存入开发者设置的网络请求适配器工厂(例如RxJavaCallAdapterFactory)和系统默认的网络请求适配器工厂(ExecutorCallAdapterFactory)

      • ExecutorCallAdapterFactory里存了MainThreadExecutor实例
    • 返回Retrofit实例

    
    	public Retrofit build() 
    
          //必须调用 baseUrl() 这个函数传入基本的url,这里才不会抛异常
          if (baseUrl == null) 
            throw new IllegalStateException("Base URL required.");
          
          //开发者是否传入OkHttpClient实例,未传入则创建
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) 
            callFactory = new OkHttpClient();
          
          //开发者是否传入 用于回调的线程池类,未传入则获取对应平台(这里是Android类)的回调线程池实例
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) 
            //这里的Platform = Android
            //platform.defaultCallbackExecutor()获取的是MainThreadExecutor实例
            callbackExecutor = platform.defaultCallbackExecutor();
          
    
          // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
          //将MainThreadExecutor装载进ExecutorCallAdapterFactory工厂实例里,并将工厂实例添加进 网络请求适配器的集合里
          callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories =
              new ArrayList<>(1 + this.converterFactories.size());
    
          // 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);
    
          //Collections.unmodifiableList()函数是将集合转化成只读的
          return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
              unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
        
    

b. 创建请求接口的实例

  • 1.retrofit.create(): 使用动态代理模式对网络请求接口类进行代理,返回代理接口的实例,这里invoke函数的代码在下面调用网络请求接口的函数时会被执行,重点在下面

    
    	public <T> T create(final Class<T> service) 
    
    	    //检查网络请求接口类是不是接口,有没继承其他接口 等
    	    Utils.validateServiceInterface(service);
    	    //判断是否需要提前缓存ServiceMethod对象, validateEagerly默认为false
    	    if (validateEagerly) 
    	      eagerlyValidateMethods(service);
    	    
    	    // 使用动态代理模式拿到 网络请求接口类的函数的注解、函数参数、函数返回值等相关信息
    	    // 返回"接口调用实例Call",其实这个Call是ExecutorCallbackCall类(Retrofit的Call的实现类)的实例,这里只要先记得返回值是ExecutorCallbackCall类的实例即可
    	    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, @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);
    	              
    
    	              //注释1:ServiceMethod接口负责存 网络请求接口类的函数的注解、函数参数、函数返回值等相关信息
    	              ServiceMethod<Object, Object> serviceMethod =
    	                (ServiceMethod<Object, Object>) loadServiceMethod(method);
    
    	            //注释2:OkHttpCall是对Retrofit.Call的实现,实际该类主要用到OkHttp.Call(rawCall这个变量) 来进行enqueue、execute请求
    	            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    
    	            //注释3:这里实际上返回的是ExecutorCallbackCall类(Retrofit的Call的实现类)的实例
    	            return serviceMethod.adapt(okHttpCall);
    	          
    	        );
    	  
    
    
    	
    

c. 调用网络请求接口的函数

  • 1.github.contributors(): 这里会回调到上一步返回的代理接口中的InvocationHandler中的invoke函数

  • 在invoke函数里拿到网络请求接口类的函数的注解、函数参数、函数返回值等相关信息,存入ServiceMethod里

  • 给ServiceMethod设置合适的数据转换器和网络请求适配器

  • 创建OkHttpCall,OkHttpCall是对Retrofit.Call的实现,实际该类主要用到OkHttp.Call(rawCall这个变量) 来进行enqueue、execute请求

  • 最后返回 ExecutorCallbackCall类(Retrofit的Call的实现类)的实例

    在上面的invoke函数中,最重要的是标有 “注释1”、“注释2” 和 “注释3” 这3行代码,先看注释1的代码

    
    	//注释1:ServiceMethod接口负责存 网络请求接口类的函数的注解、函数参数、函数返回值等相关信息
    	ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
    
    
    	public final class Retrofit 
    
    		 /**
    		   * 该函数主要加载网络请求接口类的函数的注解、函数参数、函数返回值等相关信息
    		   * 先从缓存中查找是否有该method对应的ServiceMethod实例,有则返回,没有则创建之后返回
    		   */
    		  ServiceMethod<?, ?> loadServiceMethod(Method method) 
    
    		    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    		    if (result != null) return result;
    		
    		    synchronized (serviceMethodCache) 
    		      result = serviceMethodCache.get(method);
    		      if (result == null) 
    		        //解析注解配置得到了ServiceMethod,ServiceMethod同样是Build模式创建
    		        result = new ServiceMethod.Builder<>(this, method).build();
    		        //存进缓存里
    		        serviceMethodCache.put(method, result);
    		      
    		    
    		    return result;
    		  
    	
    

    上面的ServiceMethod是通过Build模式创建的

    
    	final class ServiceMethod<R, T> 
    		static final class Builder<T, R> 
    			
    			Builder(Retrofit retrofit, Method method) 
    		      this.retrofit = retrofit;
    		      this.method = method;
    		      //获取网络请求接口里函数的注解
    		      this.methodAnnotations = method.getAnnotations();
    		      //获取网络请求接口里函数的参数类型
    		      this.parameterTypes = method.getGenericParameterTypes();
    		      //获取网络请求接口里函数的参数注解
    		      this.parameterAnnotationsArray = method.getParameterAnnotations();
    		    
    
    
    
    			public ServiceMethod build() 
    
    		      //createCallAdapter函数是从callAdapterFactories集合里找到合适的网络请求适配器
    		      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?");
    		      
    		      //createResponseConverter函数是从converterFactories集合里找到合适的数据转换器
    		      responseConverter = createResponseConverter();
    		
    		      for (Annotation annotation : methodAnnotations) 
    		        parseMethodAnnotation(annotation);
    		      
    			
    				...省略部分代码
    			
    		
    	
    
    

    上面build函数中调用createCallAdapter函数生成callAdapter,调用createResponseConverter函数生成responseConverter,这两个函数留到下一篇Retrofit源码解析(二)再去剖开,有时就应该点到即止,不然太多的细节绕着绕着就晕了,先记住这两个函数是获取了网络请求适配器和数据转换器,

    根据上面的请求函数的返回值Call<List< Contributor >>,这里获取到的网络请求适配器是ExecutorCallAdapterFactory(封装MainThreadExecutor的工厂类),获取到的数据转换器是开发者通过api设置的GsonConverterFactory

    .addConverterFactory(GsonConverterFactory.create())

    接着回到注释2的代码,可以看到主要创建了OkHttpCall,而OkHttpCall是实现了Retrofit.Call接口, 实际上该类主要用到OkHttp.Call(rawCall这个变量) 来发起enqueue(异步)或execute(同步)请求,所以OkHttpCall是封装了OkHttp框架的enqueue(异步)和execute(同步)请求

    
    	final class OkHttpCall<T> implements Call<T> 
    
    		//...省略部分代码
    
    		private @Nullable okhttp3.Call rawCall;
    		
    		//异步请求
    		@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 
    		          //createRawCall() 返回的是 OkHttp.RealCall类的实例
    		          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)