【10】注解反射动态代理实现简版Retrofit

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

注解反射动态代理实现简版Retrofit

1.Retrofit简介

Retrofit是一个RESTful的HTTP网络请求框架的封装,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装。

2.Retrofit基本使用

在这里插入图片描述

1)url由baseUrl与path拼接而成组成完整的地址。
(2)参数在get与post两个方法当中进行传递
(3)通过Retrofit的create方法,将接口对象传递进去,就可以使用接口对象调用接口里面的方法,即可得到一个Call<ResponseBody>.4)这个call对象有一个enqueue方法来进行异步请求

2.1构建者设计模式

2.1.1有什么好处?

(1)可以将一个复杂对象的构建和它的表示分离,可以使使用者不必知道内部组成的细节。
(2)构建者类会有很多成员变量或方法,表现层不需要关心其实现的细节,如变量的初值检查与设置等。

3.简易版retrofit实现

3.1实现时序图与逻辑

在这里插入图片描述

(1)执行代理方法
(2)反射获取方法上的注解
(3)反射获取方法参数上的注解
(4)记录请求参数中的参数名称

3.2构建自定义的Retrofit

3.2.1构建
	/**
     * 构建者模式,将一个复杂对象的构建和它的表现层分离,可以使使用者不用关心细节的实现
     * 这个类会有很多成员变量或方法,不需要关心其实现的细节
     */
    public static final class Builder{

        private HttpUrl      baseUrl;

        private Call.Factory callFactory;

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

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

        /**
         * 1.build()方法用于对属性做检查
         * 1.1只需要关心哪些成员是想要去设置的
         * @return
         */
        public CustomRetrofit build(){
            if(null == baseUrl){
                throw new IllegalStateException("Base URL required.");
            }

            Call.Factory callFactory = this.callFactory;

            if(null == callFactory){
                callFactory = new OkHttpClient();
            }

            return new CustomRetrofit(callFactory,baseUrl);
        }

    }
3.2.2创建请求代理类
3.2.2.1定义请求注解
@Target({ElementType.METHOD})//指定注解作用于类的哪些元素上面
@Retention(RetentionPolicy.RUNTIME)//注解由JVM保留,在运行时可以使用它
public @interface POST {
    String value() default "";
}
@Target({ElementType.METHOD})//指定此注解可作用于类的哪些元素上
@Retention(RetentionPolicy.RUNTIME)//设置注解保留级别为RUNTIME,即可由JVM保留,在运行时还可以使用它
public @interface GET {
    String value() default "";
}
3.2.2.2定义请求接口
public interface CustomWeatherApi {

    @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);
}
3.2.2.3创建接口实现类
	/**
     * 1.目的
     * 1.1返回一个接口的对象给外部
     * 1.2通过动态代理的方式去创建该接口的具体实现类对象
     *
     * 2.定义泛型方法
     * 2.1在访问修饰符与返回类型之间加个<T>,表示该方法为泛型方法
     * 2.2T:表示泛型方法的返回值也是一个泛型
     * 2.3.Class<T> service:是使用泛型作为泛型方法的参数
     *
     * 3.解析方法上的所有注解信息
     * 3.1完成url的拼接
     * 3.2完成方法的调用
     *
     * @param service:指的是CustomWeatherApi接口的class对象,此处用泛型参数去接收
     * @param <T>
     * @return
     */
    public <T> T create(final Class<T> service){

        InvocationHandler ih = new InvocationHandler() {
            /**
             * 执行代理对象的任意一个方法,都会使得invoke()方法获得执行。
             * @param o
             * @param method
             * @param objects
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                //1.解析这个方法上所有的注解信息
                //1.1就能够知道需要通过哪种请求方式(get与post)请求
                //1.2通知知道请求哪一个方法
                ServiceMethod serviceMethod = loadServiceMethod(method);

                //1.3执行方法
                return serviceMethod.invoke(objects);
            }
        };

        //使用动态代理创建CustomWeatherApi接口的实现类对象
        return (T) Proxy.newProxyInstance(service.getClassLoader(),
                new Class[]{service},ih);
    }

    /**
     * 解析方法上的所有注解信息
     * @param method
     * @return
     */
    private ServiceMethod loadServiceMethod(Method method) {
        //1.从缓存中取出方法相关的信息
        ServiceMethod result = serviceMethodCache.get(method);
        if(null != result){
            return result;
        }

        //2.利用同步代码块细粒度的上锁
        synchronized (serviceMethodCache){
            //2.1先从缓存中取方法信息
            result = serviceMethodCache.get(method);
            //2.2判断是否有方法信息,没有则新建后放入缓存
            if(null == result){
                result = new ServiceMethod.Builder(this,method).build();
                serviceMethodCache.put(method,result);
            }
        }

        return result;
    }

3.3构建方法解析器

3.3.1GET请求参数注解
@Target({ ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
    String value() default "";
}
3.3.2POST请求参数注解
@Target({ ElementType.PARAMETER})//指定该注解可以运用于标记类的哪些元素上面,此处为方法参数
@Retention(RetentionPolicy.RUNTIME)//指定注解保留级别为RUNTIME级别,可由JVM保留,即在JVM运行的时候还可以使用它
public @interface Field {
    String value() default "";
}
3.3.3构建方法解析器对象
	public static class Builder{
        private final CustomRetrofit retrofit;

        //存放方法上的所有注解
        private final Annotation[] methodAnnotations;

        //存放方法参数里面的所有注解信息
        private final Annotation[][] parameterAnnotations;
        //存放方法参数请求的key
        private ParameterHandler[]   parameterHandlerArr;

        //记录当前的请求方式
        private String httpMethod;
        //记录请求url的path
        private String relativeUrl;
        //判断是否有请求体
        private boolean hasBody;

        /**
         * 1.外部传递需要
         * 2.Method method
         */
        public Builder(CustomRetrofit retrofit, Method method){
            this.retrofit = retrofit;
            this.methodAnnotations = method.getAnnotations();
            this.parameterAnnotations = method.getParameterAnnotations();
        }

        /**
         * 1.在build方法中对成员变量做相应的设置
         * @return
         */
        public ServiceMethod build(){

            for(Annotation methodAnnotation : methodAnnotations){
                if(methodAnnotation instanceof POST){
                    this.httpMethod = "POST";
                    this.relativeUrl = ((POST) methodAnnotation).value();
                    this.hasBody = true;
                }else if(methodAnnotation instanceof GET){
                    this.httpMethod = "GET";
                    this.relativeUrl = ((GET) methodAnnotation).value();
                    this.hasBody = false;
                }
            }

            //2.解析方法参数的注解
            int length = parameterAnnotations.length;
            parameterHandlerArr = new ParameterHandler[length];
            for(int i =0; i < length; i++){
                //2.1取得一个参数上的所有注解
                Annotation[] annotations = parameterAnnotations[i];
                for(Annotation annotation : annotations){
                    //方法参数被Field注解修饰的为post请求,被Query注解修饰的为get请求
                    if(annotation instanceof Field){
                        //得到注解上的value,即获取请求参数的中的key
                        String value = ((Field)annotation).value();
                        parameterHandlerArr[i] =
                                new ParameterHandler.FieldParameterHandler(value);
                    }else if(annotation instanceof Query){
                        String value = ((Query)annotation).value();
                        parameterHandlerArr[i] =
                                new ParameterHandler.QueryParameterHandler(value);
                    }
                }
            }

            return new ServiceMethod(this);
        }
    }
3.3.4构建参数处理器
public abstract class ParameterHandler {

    abstract void apply(ServiceMethod serviceMethod,String value);

    /**
     * get请求的参数拼接
     */
    static class QueryParameterHandler extends ParameterHandler{

        String key;

        public QueryParameterHandler(String key) {
            this.key = key;
        }

        @Override
        void apply(ServiceMethod serviceMethod, String value) {
            //拼接方法参数到url中
            serviceMethod.addQueryParameter(key,value);
        }
    }


    /**
     * post请求的参数拼接
     */
    static class FieldParameterHandler extends ParameterHandler{

        String key;

        public FieldParameterHandler(String key) {
            this.key = key;
        }

        @Override
        void apply(ServiceMethod serviceMethod, String value) {
            serviceMethod.addFieldParameter(key,value);
        }
    }
}
3.3.5参数拼接
    //get请求,把参数key与value拼接到请求url中
    public void addQueryParameter(String key, String value) {
        if(null == urlBuilder){
            urlBuilder = baseUrl.newBuilder(relativeUrl);
        }
        urlBuilder.addQueryParameter(key,value);
    }

    //post请求,将参数key与value直接添加到表单请求体中。
    public void addFieldParameter(String key, String value) {
        formBuild.add(key,value);
    }

3.4请求方法调用执行

	//执行方法
    public Object invoke(Object[] args){
        /**
         * 1.处理请求的地址与参数
         */
        for(int i = 0; i < parameterHandlerArr.length; i++){
            ParameterHandler handler = parameterHandlerArr[i];
            //为参数中的key设置对应的值
            handler.apply(this,args[i].toString());
        }

        //获取最终请求地址
        HttpUrl url;
        if(null == urlBuilder){
            urlBuilder = baseUrl.newBuilder(relativeUrl);
        }
        url = urlBuilder.build();

        //post请求时的表单请求体
        FormBody formBody = null;
        if(null != formBuild){
            formBody = formBuild.build();
        }

        Request request =
                new Request.Builder().url(url).method(httpMethod,formBody).build();

        return callFactory.newCall(request);
    }

3.5.客户端调用

//通过注解、反射、动态代理自定义retrofit,实现post请求与get请求
        CustomRetrofit customRetrofit = new CustomRetrofit.Builder().baseUrl(baseUrl).build();
        //customWeatherApi对象其实是一个代理对象,然后通过这个代理对象去执行get方法和post方法。
        customWeatherApi = customRetrofit.create(CustomWeatherApi.class);
btn_myretrofit_post.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                okhttp3.Call call = customWeatherApi.postWeather("110101", "ae6c53e2186f33bbf240a12d80672d1b");
                call.enqueue(new okhttp3.Callback() {

                    @Override
                    public void onFailure(okhttp3.Call call, IOException e) {

                    }

                    @Override
                    public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                        if(response.isSuccessful()){
                            Log.i(CUSTOM_TAG,
                                    "onResponse enjoy post: " + response.body().string());
                            response.close();
                        }
                    }
                });
            }
        });

4.打赏鼓励

感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!

4.1微信打赏

在这里插入图片描述

4.2支付宝打赏

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值