Retrofit框架源码学习

2020-04-09  本文已影响0人  浪里_个郎

引用和参考:
从架构角度看Retrofit的作用、原理和启示
Retrofit分析-漂亮的解耦套路

本文有以下内容:
1,Retrofit用于解决什么问题
2,Retrofit怎么实现Request的封装
3,Retrofit中有哪些功能扩展,或者说有哪些可供用户自定义的部分
4,Retrofit有哪些值得学习的设计思想

1,Retrofit用于解决什么问题

Retrofit内部使用了自家的OKHttp来实现网络请求,如果简单的使用,OKHttp已经很方便了,但如果需要定义大批量的Request,就要写很多重复代码。并且网络请求通常使用Rxjava处理并发,不同库之间组合使用时也相对麻烦。
Retrofit简化了这些重复性的代码。我们只需要定义一个网络请求接口,加上注解,Retrofit就能帮我们生成Request并交给OKHttp处理,并且能根据我们的需求,返回生成OKHttp的Call对象或Rxjava的Observable对象,将返回内容解析成我们需要的类型。
Retrofit基本使用流程:

        //1,创建OkHttpClient
        sOkHttpClient = new OkHttpClient.Builder()
                ...
                .addInterceptor(InterceptorUtil.getCacheInterceptor())
                .build();
        //2,使用Build模式创建Retrofit
        sRetrofit = new Retrofit.Builder()
                .baseUrl(sBaseUrl) //主页
                .client(sOkHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        //3,定义网络请求API
        public interface LoginApi {
          public static final String HOST = "http://www.wanandroid.com/tools/mockapi/2164/";
          //通过注解封装url请求,接在主页后面
          @GET("hotchpotch_login")
          Observable<BaseResponse<Login>> login();
        }
        //4,通过Retrofit将网络请求API转换为实际的网络请求,并获取返回值
        return sRetrofit.create(LoginApi.HOST,LoginApi.class);

2,Retrofit怎么实现Request的封装

Retrofit封装

自定义interface里有注解的方法:

@GET("hotchpotch_login")
Observable<BaseResponse<Login>> login();

注解中可以描述url和请求方式,Retrofit解析注解并封装进ServiceMethod。通过ServiceMethod可以获取Request:

Request request = serviceMethod.toRequest(args);

其中的解析和转换,是在Retrofit.create(XXX.class)方法中通过动态代理完成的。XXX.class代表自定义接口,里面定义了带注解的方法,代表Request需求。

关于动态代理

我们把定义好的网络访问接口传给Retrofit,就能得到一个可以调用的实现类,这就使用了JDK中Proxy和InvocationHandler组合的动态代理。
proxy的方法:

Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2)

会返回代理类,每当通过代理调用var1(目标类)中方法时,都会变为调用var2中的

Object invoke(Object var1, Method var2, Object[] var3)

invoke函数实现的返回值需要和自定义接口中方法的返回值一致。invoke函数中会帮我们自动实现接口中方法的功能,生成代理类:

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    validateServiceInterface(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 @Nullable
          Object invoke(Object proxy, Method method,
                        @Nullable Object[] args) throws Throwable {
            // 如果是Object中的方法,就正常调用
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //根据系统平台,生成接口的实现代码
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //将自定义接口的方法转为ServiceMethod,返回自定义接口的代理类
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

3,Retrofit中有哪些功能扩展,或者说有哪些可供用户自定义的部分

这个问题,其实涉及到Retrofit框架的开发原因。
对于一个网络请求,有哪些变量?
url、请求方式(get/post等)、Http请求的Header设置与安全设置等,以及返回的数据类型。
针对易变的url和请求方式,Retrofit使用了方法注解的方式,可读性良好,扩展性优异,但这需要实现对接口函数中注解的解析,这样就有了ServiceMethod。
针对Http请求的各种设置,其实Retrofit没做什么,因为Retrofit使用的OkHttp有拦截器机制,可以应付这种变化。
针对返回的数据类型,默认情况下,Retrofit会把HTTP响应体反序列化到OkHttp的ResponseBody中,加入Converter可以将返回的数据直接格式化成你需要的样子。由于目标数据类型与业务有关,是不确定的,Retrofit无法提供一个万能的转换类,所以Retrofit提供了扩展接口,允许开发者自己定义ConverterFactory和Converter,去实现潜在的数据类型转换。
针对返回的网络工作对象,对于OKHttp来说,一个请求返回的是okhttp3.call这个Call接口,但如果我们要返回Rxjava的ObServable或Flowable接口的网络工作对象,可以使用addCallAdapterFactory添加CallAdapterFactory。
GsonConverterFactory和RxJava2CallAdapterFactory都是Retrofit帮我们写好的,如果有需要,我们可以自己扩展。添加扩展的示例代码如下:

sRetrofit = new Retrofit.Builder()
    .baseUrl(baseUrl)
    .client(sOkHttpClient)
    .addConverterFactory(GsonConverterFactory.create()) //可以把Http访问得到的json字符串转换为Java数据对象BizEntity
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //Rxjava网络工作对象
    .build();
return sRetrofit.create(tClass);

下面定义的请求,返回的是Observable网络工作对象,返回值为Gson转成的BaseResponse类。

public interface LoginApi {
    public static final String HOST = "http://www.wanandroid.com/tools/mockapi/2164/";
    //自定义接口与返回数据模拟返回统一格式数据封装(http://www.wanandroid.com/tools/mockapi)
    @GET("hotchpotch_login")
    Observable<BaseResponse<Login>> login();
}

4,Retrofit有哪些值得学习的设计思想

stay4it大神的流程图

在设计模式的使用上,首先通过外观模式,用Retrofit类封装了各个功能模块的接口,在使用方便的同时,将用户代码和实际的功能模块解耦。
然后,通过动态代理模式,将用户通过注解定义的接口中的方法生成网络请求。
再往后,就是通过适配器模式,将OKHttp的返回适配成用户需要的类型。
另外,就是框架对于面向对象原则的坚持。哪怕是使用自家的OkHttp,哪怕底层使用了OkHttpClient去处理网络请求,但她并没有使用okhttp3.call这个Call接口,而是自己又建了一个retrofit2.Call接口,OkHttpCall继承的是retrofit2.Call,与okhttp3.call只是引用关系。这样的设计符合依赖倒置原则,可以尽可能的与OkHttpClient解耦。

其实,对于设计的体会,是随着自己的经验不断增加的,过一段时间再来看源码,可能又是一堆新的体验。

上一篇下一篇

猜你喜欢

热点阅读