定制Retrofit

935 阅读3分钟

定制目的

我们的最终目的是将中间层拿掉,直接集成okhttp的包装框架,JLRetrofit的存在其实就是来兼容我们老的逻辑,让各端能平滑过渡,慢慢迁移。

架构图

博客内容

  1. 了解Retrofit背后的知识,深入理解
  2. 分析Mini版Retrofit框架代码

理解Retrofit

下面详细了解下四个知识点,懂了之后你就会发现,retrofit真的很简单。 最核心的四个知识点

  • 注解
  • 动态代理
  • 反射
  • 设计模式

注解

注解原理点我或者直接看下图

注解

动态代理

原理请看点我

反射

原理请看点我

设计模式

整个流程中运用的设计模式如下 设计模式

流程图

分析Mini版Retrofit框架代码

我们分析的流程如下: 分析POST注解->如何解析出POST注解内容->根据解析的数据发送POST请求

POST注解

@Documented //注释放到javaDoc中
@Target(METHOD) //注释目标是方法
@Retention(RUNTIME) // 运行时保留
public @interface POST {
  /**
   * A relative or absolute path, or full URL of the endpoint. This value is optional if the first
   * <p>
   * this is resolved against a base URL to create the full endpoint URL.
   */
  String value() default "";  
}

如何解析出POST注解内容

通过搜索查到这,这里判断了注解Annotation 是否是POST类型,是就解析POST类型需要的其他字段

  private void parseMethodAnnotation(Annotation annotation) {
            if (annotation instanceof POST) {
                this.parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
            }
        }

往上层继续找,RequestFactory build函数里,对一个变量methodAnnotions遍历解析,再找一下this.methodAnnotations哪里来的

  RequestFactory build() {
            Annotation[] var1 = this.methodAnnotations;
            int p = var1.length;
            int lastParameter;
            for (lastParameter = 0; lastParameter < p; ++lastParameter) {
                Annotation annotation = var1[lastParameter];
                this.parseMethodAnnotation(annotation);
            }

同样还在RequestFactory类中,通过Method类method.getAnnotations()获取的。

     Builder(JLRetrofit retrofit, Method method) {
            this.retrofit = retrofit;
            this.method = method;
            this.methodAnnotations = method.getAnnotations();
            this.parameterTypes = method.getGenericParameterTypes();
            this.parameterAnnotationsArray = method.getParameterAnnotations();
        }

继续往上找,静态函数,parseAnnotations传递过来。

    static RequestFactory parseAnnotations(JLRetrofit retrofit, Method method) {
        return (new RequestFactory.Builder(retrofit, method)).build();
    }

继续,ServiceMethod抽象类,parseAnnotations函数中调用

   static <T> ServiceMethod<T> parseAnnotations(JLRetrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        Type returnType = method.getGenericReturnType();
        if (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.");
        }
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }

继续,在Retrofit类中 函数loadServiceMethod中调用。

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

        synchronized (serviceMethodCache) {
            result = serviceMethodCache.get(method);
            if (result == null) {
                result = ServiceMethod.parseAnnotations(this, method);
                serviceMethodCache.put(method, result);
            }
        }
        return result;
    }
    public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service}, new InvocationHandler() {
            private final Object[] emptyArgs = new Object[0];

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                if (method.getDeclaringClass() == Object.class) {
                    return method.invoke(this, args);
                }
                return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
            }
        });
    }

最终看到了create函数,这个函数就是我们在创建api的过程中经常用到的函数。

   Call<String> call = new JLRetrofit.Builder().baseUrl("http://").build().create(ServiceApi.class).getBaidu();
        try {
            call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

根据解析的数据发送POST请求

一个网络最终调用execute接口发送请求的,肯定有实现类,要不然如何请求的呢。option+command+B 看图

接口实现
这里发现两个,最终发送网络请求的其实是OkhttpCall,这里实现了Okhttp的调用。看图,call是okhttp3包下的类
OkhttpCall
为什么有两个呢?这里用到一个设计模式,装饰者模式,跟我们RecylerView 的adapter一个概念,我们可以添加更多的Adapter来处理数据。 看类名ExecutorCallbackCall可以猜到,这是一个线程管理装饰者,负责异步处理的。 网络请求的参数哪里来的呢,其实所有的参数和注解的内容已经解析出来存在RequestFactory中。

    OkHttpCall(RequestFactory requestFactory, Object[] args) {
        this.requestFactory = requestFactory;
        this.args = args;
    }

如图:url、body、httpMethod都会在这个类里解析出来。

RequestFactory
整个流程分析完了,准备的比较仓促,不全面,抱歉啊,接下来直接看源码吧。

总结

一个Retrofit框架,整体设计结构蕴藏着很多设计模式,很多良好的代码书写习惯。多分析,多看看,还是有很多收获的。分享就到这,有问题请留言。