定制Retrofit

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 定制Retrofit

定制目的


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

image.png

博客内容


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

理解Retrofit


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

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

注解


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

16cfc566e57cc366_tplv-t2oaga2asx-zoom-in-crop-mark_4536_0_0_0 (1).jpg


动态代理


原理请看点我

反射


原理请看点我

设计模式


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

16cfc566e5966607_tplv-t2oaga2asx-zoom-in-crop-mark_4536_0_0_0.jpg

分析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 看图

image.png

这里发现两个,最终发送网络请求的其实是OkhttpCall,这里实现了Okhttp的调用。看图,call是okhttp3包下的类

image.png

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

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

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

image.png

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

总结


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



目录
相关文章
|
3月前
retrofit+okhttp+rxjava
retrofit+okhttp+rxjava
|
5月前
|
JSON Java 数据格式
rxjava2+retrofit2
rxjava2+retrofit2
47 1
|
缓存
Retrofit配置及各情况处理
Retrofit配置及各情况处理
195 0
|
JSON 安全 Java
Retrofit入门
Retrofit入门
|
JSON Android开发 数据格式
RxJava+Retrofit示例 ,Retrofit 注解学习
RxJava+Retrofit示例 ,Retrofit 注解学习
158 0
|
API Android开发 Java
RxJava2 和 Retrofit2 结合使用详解
不讲 rxjava 和 retrofit 而是直接上手 2 了,因为 2 封装的更好用的更多。 1. 观察者模式 常见的 button 点击事件为例,button 是被观察者,listener 是观察者,setOnClickListener 过程是订阅,有了订阅关系后在 button 被点击的时候,监听者 listener 就可以响应事件。
|
缓存 API Android开发
浅谈OkHttp以及Retrofit+RxJava的封装使用
1.为什么我们要使用OkHttp?OkHttp有什么优点?  说OkHttp之前我们先说另外两个网络请求库——HttpUrlConnection和HttpClient。
2202 0
|
Android开发 Java
|
Java Android开发 流计算
|
Java Android开发
Android/Java网络加载框架Retrofit(一)初识
Android/Java网络加载框架Retrofit(一)初识Retrofit是Square针对Android网络I/O设计的一套框架。
1094 0