Retrofit的简单使用和源码分析

转载请标明出处: https://blog.csdn.net/static_zh/article/details/97391537

现在比较流行的网络框架一个是OKHttp,一个就是Retrofit,在研究这个两个框架之前,我一直以为它们两个是同等级别的,后来才知道原来OKHttp数据底层的网络访问框架,和HttpUrlConnection、HttpClient同一个级别的,而Retrofit是在OKHttp的基础上进行了封装,比如使用注解来配置参数,可以自定义不同序列化工具,数据返回自动到主线程等。

如果我们只使用OKHttp来作为网络访问框架,就需要自己处理封装,比如最简单的,请求到的Response后如果要更新UI,要自己处理发送到主线程,而Retrofit这样的框架都已经封装好了的。

简单的使用

1)在build.gradle中添加依赖
compile 'com.squareup.retrofit2:retrofit:2.6.0'
//gson解析器,如果不适用Gson解析返回的结果,可以不依赖这个库
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
2)创建Retrofit对象
 Retrofit retrofit = new Retrofit.Builder()
          .baseUrl("https://192.168.220.45/am/") 
          .addConverterFactory(GsonConverterFactory.create()) //定义序列化工具,这里用的Gson
          .build();
3)创建访问接口
public interface IUser {
    @GET("user")
    Call<User> getUser();
}

这里以GET请求为例,上面注解中的 user,最终和 baseUrl 拼接到一起组成https://192.168.220.45/am/user去访问服务器。

4)发起请求
//创建对应的接口对象
IUser iUser = retrofit.create(IUser.class);
//调用接口中的方法
Call<User> call = iUser.getUser();
//发起请求
call.enqueue(new Callback<User>() {
      @Override
      public void onResponse(Call<User> call, Response<User> response) {
           //运行在主线程
           User body = response.body();
           Log.e(TAG,body.toString());
      }

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

        }
});

以上就是Retrofit的用法,很简单,流式代码的调用很方便,使用建造者模式来自定义参数,在第一次使用这个框架的时候最大的疑问就是为什么只需要定义一个接口就能获取到接口的对象,然后调用方法就可以发起访问,下面从源码的角度来说一下Retrofit的访问流程。

源码分析

1)build方法

建造者模式很常见了,不管是EventBus还是OKHttp这些框架都是使用这种设计模式来让用户进行自定义的参数配置,如果使用者没有进行对应参数的配置,内部会有默认的配置,我们先来看看在创建Retrofit的时候都进行了哪些参数的配置,代码如下

public Retrofit build() {
      if (baseUrl == null) {  //注释A
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;  //注释B
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;  //注释C
      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));  //注释D

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());  //注释E
	  ...
      ...
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  • 在注释A处,我们看到先去判断了baseUrl有没有设置,如果没有设置直接就抛出异常了

  • 在注释B处,创建了callFactory,可以看到如果这个变量为null,会自己创建一个 OkHttpClient对象,我们可以知道callFactory对象就是用来最终请求的对象,我们说Retrofit内部使用的OKHttp来完成网络访问的,其实就是在这里创建的OKHttpClient对象,同样从这里可以看出来,我们可以自定义callFactory,我们是可以把OKHttp换掉的。

  • 在注释C处,是创建参数Executor,如果用户没有设置会创建了一个默认的,它的作用是将最后的请求结果发送的主线程

  • 在注释D处,是创建参数CallAdapter,如果用户没有设置会创建了一个默认的CallAdapter,从名称上来看这个参数是一个适配器,既然是个适配器就可以扩展适配器的类型,可扩展的类型有RxjavacalllAdapter、java8callAdapter、DefultCallAdapter、 ExecutorCallAdapter等。它的作用对Call进行转化,相当于把OKHttp的Call进行了一次封装

  • 在注释E处,因为上面的例子中使用了GsonConverterFactory,所以这里会使用GsonConverterFactory作为序列化工具

Retrofit支持的序列化工具如下:

Gson: com.squareup.retrofit2:converter-gson 
Jackson: com.squareup.retrofit2:converter-jackson 
Moshi: com.squareup.retrofit2:converter-moshi 
Protobuf: com.squareup.retrofit2:converter-protobuf 
Wire: com.squareup.retrofit2:converter-wire 
Simple XML: com.squareup.retrofit2:converter-simplexml

最后用这几个参数创建出Retrofit对象。

2)create方法

在创建出Retrofit对象以后,会调用create方法,看下面的源码

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //注释A
    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 @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            ...
            ...          
            //注释B
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
  • 注释A处,使用的是java中提供的动态代理类,如果对动态代理、静态代理不熟悉的,接着向下看,这里使用Java中提供的动态代理类,返回了动态代理的类对象
  • 注释B出,在invoke方法中最后调用了 loadServiceMethod 方法,将method对象传入,然后调用invoke方法。
动态代理

把上面的动态代理的代码简化一下如下:

public interface IUser {
    @GET("user")
    Call<User> getUser();
}

public static void main(String[] args)
{
    IUser iUser = (IUser) Proxy.newProxyInstance(IUser.class.getClassLoader(), new Class<?>[]{IUser.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());
            return null;
        }
    });
    iUser.getUser();
}

如上,运行代码以后,会打印调用的方法名和注解的名字,可以看到通过Proxy的newProxyInstance方法,然后传入接口类的类加载器和Class对象,就能够得到一个接口的对象,然后当用这个对象在调用接口中的方法的时候,在InvocationHandler对象中的invoke方法中可以拦截方法的名称、参数、注解。

动态代理指的是代码的运行的过程中动态生成代理类,然后通过反射的方式调用目标类的方法。如果你去看j上面的Proxy的源码,也是使用反射的方式来完成调用的,好处是在代码运行当中就可以拦截方法,可以在调用方法的前后做一些事情。

理解了什么是动态代理,你就知道了,为什么Retrofit在使用的时候,我们只需要定义一个接口,就可以获取到这个接口的对象。

3)调用接口中的方法

如上的例子就是调用 getUser方法,上面使用动态代理获取了接口类的对象,接着就是用对象调用接口中具体的方法,我们知道在调用方法的时候就会调用动态代理中的invoke方法,看上一步中注释 B 处的代码,调用了loadServiceMethod方法,代码如下:

ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //注释A
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这个方法中的逻辑比较简单,主要是通过Method去向缓存中获取ServiceMethod,如果缓存中没有,就去解析传入的Method生成ServiceMethod,放入缓存,返回。

注释A处代码是解析的位置,代码如下

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

代码不多,没有精简,其中最主要的看注释A,看方法名可以知道又去解析注解了,代码如下

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
     ...
     ...
     ...
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    
  }

这里面的代码很多,主要的逻辑就是解析注解,我们只看最后返回一个CallAdapted对象,注意这个对象的参数,参二 callFactory,就是开始设置的HttpClient对象,参四就是开始设置的放入callAdapterFactories集合中的callAdapter,过一会我们会回去找它们。

好到此 loadServiceMethod方法就返回完毕了,经过几层的调用,最后返回了一个CallAdapted对象,然后我们在回看动态代理invoke中的方法,调用完 loadServiceMethod之后又调用了它的invoke方法,当然就是CallAdapted的invoke方法, CallAdapted 类如下

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

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

    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

发现没有invoke方法,肯定在它的父类中,可以看到它的父类是 HttpServiceMethod,在这个类中找到了invoke方法,如下

@Override 
final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

invoke方法只有两行代码,第一行创建一个OKHttpCall对象,然后调用adapt方法,将创建的Call对象传入,进入到OKHttPCall中,发现这个类就是对OKHttp的封装类,内部使用OKHttp去访问网络请求数据,然后接着找adapt方法,发现在 HttpServiceMethod中的adapt方法是一个抽象方法

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

实现肯定是在它的子类里面,那就想到之前的 CallAdapted 类,在这个类中找到了adapt方法,如下

@Override 
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }

在这个方法中调用了callAdapter的adapt方法,还记得之前我们说的callAdapter是谁吗,就是最一开始build方法中创建的默认的callAdapter,回看之前的代码

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
        //注释A
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      //注释B
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
  • 注释A处,创建了默认的Executor
  • 注释B处,创建了默认的CallAdapter,然后把创建的Executor传入

先看看创建默认Executor的代码,后面会使用到它将请求结果发送到主线程,defaultCallbackExecutor代码如下:

 @Override 
public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
}

 static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

代码比较简单,就是创建了主线程Handler,发送到主线程执行

接着找CallAdapter,看看defaultCallAdapterFactories的代码

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    return singletonList(new DefaultCallAdapterFactory(callbackExecutor));
  }

可以看到,在这个方法中创建了DefaultCallAdapterFactory对象,进去看看

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

    
  @Override 
    public @Nullable CallAdapter<?, ?> get(			//注释A
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
  	...
    ...
    
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call); //注释B
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override 
	public void enqueue(final Callback<T> callback) {
	  //注释C
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          //注释D
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {         
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
    @Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }

  }
}
  • 注释A处,通过 get 方法获取到 CallAdapter对象

  • 注释B处,调用adapt方法,返回 ExecutorCallbackCall对象,接收的call 参数就是OKHttpCall对象

  • 注释C处,封装了异步请求方法enqueue,内部实际是使用的 delegate对象去执行的 enqueuedelegate对象就是OKHttpCall

  • 注释D处,callbackExecutor调用execute 方法将返回的结果发动到主线程中

到此整个Retrofit的访问流程就分析完毕,接下来总结下整个流程和使用到的设计模式

总结时刻

1)流程总结
  1. 使用建造者模式设置各种参数,如果使用者没有自定义内部创建默认的参数
  2. 使用动态代理的方式创建接口的对象
  3. 当使用接口对象调用对应的接口方法的时候,在动态的解析方法的注解、参数等信息
  4. 将所有的解析结果存入到一个ServiceMethod对象中,然后创建对应的缓存
  5. 创建OkHttpCall对象,内部通过OKHttp进行网络请求,将请求的结果发送到主线程
2)设计模式总结
  1. 建造者模式:在创建Retrofit对象创建的时候使用的建造者模式,对外提供自定义参数,如果没有自定义采用默认的
  2. 工厂模式 : 在自定义参数的时候大部分都是采用工厂模式封装生产出来的,如addConverterFactory、addCallAdapterFactory
  3. 适配器模式:在添加CallAdapter的时候使用的是适配器模式,提供了多种支持的适配器方式,比如支持Rxjava格式
  4. 动态代理: 在创建接口对象,调用接口方法的时候使用的是动态代理的方式对方法进行了拦截,然后封装各种注解参数等

基本上就这些吧,还有一些比如策略模式、观察者模式、装饰模式这些我没有仔细研究,有兴趣可以自己看看

参考链接:
https://blog.csdn.net/lmj623565791/article/details/51304204
https://www.jianshu.com/p/45cb536be2f4
https://juejin.im/entry/59ad567df265da24777a161d

在这里插入图片描述

关注我的公众号,我们一起进步
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值