美文网首页
注解-反射-动态代理-在Retrofit中的应用

注解-反射-动态代理-在Retrofit中的应用

作者: JackDaddy | 来源:发表于2020-05-08 17:20 被阅读0次

本篇文章的目的是介绍 注解 反射 以及 动态代理Retrofit 框架中的体现。
首先带着几个问题去开始以下的文章:

  1. 注解在 Retrofit 中是如何体现的,有什么作用的?
  2. 反射在 Retrofit 中是如何体现的,有什么作用的?
  3. 动态代理在 Retrofit 中是如何体现的,有什么作用的?

在回答以上几个问题之前,先让本少爷来给你解释一下几个概念:

注解: 可以认为是一个标签,只是这个标签附带有数据,比如给张 三贴上一个 渣男 的标签,那这个 渣男 的标签含有的 数据 就是-张三玩弄感情的证据。

反射:那既然通过注解保存了数据信息,当然要有方法去获取到注解中数据,这个方法就是反射,通过反射去获取注解上的信息。比如有了张三现在有了渣男的标签,现在就可以通过反射去拿到张三玩弄感情的证据

代理模式:指的是通过代理对象持有对真实对象的引用,通过代理对象实现对真实对象的操作。比如张三通过 某APP 约小姐姐一起去运动

代理模式又分为静态代理与动态代理,想了解详细内容可查看本少爷代理模式的专题。

通过手写一个简易版的 Retrofit 的应用来解释他们在Retrofit中的应用:

  1. 首先要定义注解—— 规定请求的方式,参数的格式等
//自定义注解请求的方式
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
    String value() default "";
}
---------
//自定义注解-请求的参数的格式
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Field {
    String value();
}
  1. 定义网络接口,把刚才定义好的注解添加到接口的方法上,然后通过这个接口来请求数据。
    了解过Retrofit的都知道Retrofit实际上是通过okhttp去请求数据的,所以这里使用了okhttp的Call。
public interface API {

    @POST("/v3/weather/weatherInfo")
    Call postWeather(@Field("city")String city,@Field("key")String key);

    @GET("/v3/weather/weatherInfo")
    Call getWeather(@Query("city") String city, @Query("key")String key);
}
  1. 定义一个Retrofit 类,里面含有两个最重要的参数
    1)请求的地址(baseUrl)
    2)实现请求的引擎(okHttpCall)
public EasRetrofit(Call.Factory factory, HttpUrl baseUrl) {
        this.factory = factory;
        this.baseUrl = baseUrl;
    }

通过建造者模式来实现对Retrofit这个类的封装:

public static final class Builder {
        private HttpUrl baseUrl;
        private okhttp3.Call.Factory factory;

        public Builder baseUrl(String baseUrl) {
            this.baseUrl = HttpUrl.get(baseUrl);
            return this;
        }

        public Builder callFactory(okhttp3.Call.Factory factory) {
            this.factory = factory;
            return this;
        }

        public EasRetrofit build() {
            if (baseUrl == null) {
                throw new IllegalStateException("Base URL required.");
            }
            factory = this.factory;
            if (factory == null) {
                factory = new OkHttpClient();
            }
            return new EasRetrofit(factory, baseUrl);
        }
    }
  1. 通过动态代理生成第2步定义的网络接口对象
public <T> T create(Class<T> service) {
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //解析这个method 上所有的注解信息
                        ServiceMethod serviceMethod = loadServiceMethod(method);
                        //args
                        return serviceMethod.invoke(args);
                    }
                });
    }

其中InvocationHandler可以理解是一个监听,当调用到接口对象中的方法时,这个监听就会触发,就会拿到接口对象中对应的方法,对应的参数信息。

  1. 通过这个监听就可以实现对接口对应方法中的处理:
    1)处理方法上的注解,获取注解包含的数据信息
    2)封装数据信息,提供多次复用
    这个封装类就是 ServiceMethod,同样也是通过对建造者的模式进行封装。

  2. 在网络请求中肯定存在多次请求相同的情况,因此对请求信息进行一个简单的封装:

//通过 ConcurrentHashMap 来存储请求信息
private Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();
-------
 private ServiceMethod loadServiceMethod(Method method) {
        //先不上锁,避免synchronized的性能损失
        ServiceMethod result = serviceMethodCache.get(method);
        if (result != null) {
            return result;
        }
        //多线程下,避免重复解析
        synchronized (serviceMethodCache) {
            if (null == result) {
                result = new ServiceMethod.Builder(this, method).build();
                serviceMethodCache.put(method, result);
            }
        }

        return result;
    }
  1. 返回一个okhttpCall
Request request = new Request.Builder().url(url).method(httpMethod, formBody).build();
//okhttpCall
return factory.newCall(request);

让我们来看看是如何使用的:

EasRetrofit easRetrofit = new EasRetrofit.Builder().baseUrl("https://restapi.amap.com").build();
 //可以理解是一个是一个监听,当监听到调用了接口中的方法时,就执行生成okhttpcall
 api = easRetrofit.create(API.class);
-------------------------------------------------
//获取到监听中生成的okhttpcall对象
okhttp3.Call call = api.postWeather("110101", "ae6c53e2186f33bbf240a12d80672d1b");
//通过call进行异步请求
 call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

回到一开始的三个问题,我们来简单回答一下:

  1. 注解在 Retrofit 中是如何体现的,有什么作用的?
    体现在网络接口的方法上,规定请求的格式,请求参数等。

  2. 反射在 Retrofit 中是如何体现的,有什么作用的?
    体现在解析网络接口方法上注解中包含的数据,获取请求的数据。

  3. 动态代理在 Retrofit 中是如何体现的,有什么作用的?
    体现在生成网络接口对象,封装网络请求的数据,实现一个类似于监听的功能。

最后,附上流程图: Retrofit流程图 你的一点帮助是他的无限动力~ 后浪~

相关文章

网友评论

      本文标题:注解-反射-动态代理-在Retrofit中的应用

      本文链接:https://www.haomeiwen.com/subject/ocufnhtx.html