首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Retrofit与动态代理

Retrofit与动态代理

作者头像
None_Ling
发布2019-05-22 23:04:22
8820
发布2019-05-22 23:04:22
举报
文章被收录于专栏:Android相关Android相关

什么是代理

代理,即Proxy。它的作用就是将原数据与后续的操作进行隔离,达到对修改封闭,对扩展开放的效果。

从现实生活中理解,厂商生产产品到代理商,而代理商负责找渠道销售产品。期间,厂商与销售人员不会有任何接触,也不管销售效果如何。

什么是静态代理

在Java中,通常会用代理模式来完成一些额外的操作。

例如,有一件商品,售价为25元,但是经过代理商之后,售价要提高5元。

// 定义货物的接口,以及获取价格的函数
public interface Cargo{
      public int getPrice();
}

// 定义产品,实现Cargo接口,返回25元
public class Product implements Cargo{
    @Override
    public int getPrice(){
        return 25;
    }
}

// 定义产品的代理,实现Cargo接口,并且在原有的基础上增加5元再进行销售
public class ProductProxy implements Cargo{
     private Product product;

     public ProductProxy(Product product){
           this.product = product;
     }

    @Override
    public int getPrice(){
        return product.getPrice()+5;
    } 
}
静态代理的优点
  • 隐藏委托类的实现,保证委托类的独立
  • 实现代理与委托类之间的解耦,不侵入委托类的代码

动态代理的背景

在使用静态代理的过程中,会产生如下问题:

  • 大型项目的复杂度,如果代理过多的话,会导致维护成本很大,并且难以理解
  • 通过接口实现的静态代理作用死板,对于功能的复用有很大影响

举例,我们希望统计产品在生产过程中(原材料采购 --> 材料加工 --> 产品制作 --> 后期包装等步骤)消耗的时间,然后产生报表。如果还使用静态代理的话,则这个代理类中都是相同的代码,并且后续再添加接口,仍然需要修改该代理类

于是,Java提出了动态代理的概念。

动态代理

动态代理,也就是在运行时创建的代理类。在运行过程中,会在虚拟机内部创建一个Proxy的类。通过实现InvocationHandler的接口,来代理委托类的函数调用。

public class ProductProxy implements InvocationHandler{

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

还是以上述商品来举例。

 public class ProductProxy implements InvocationHandler{
         // 被委托的对象
         private Product product;

         public ProductProxy(Product product){
                 this.product = product;
          }

        @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             if(method.getName().equals("getPrice")){
                // 如果调用的函数为getPrice的话,则+5
                  return method.invoke(product,args)+5;
             }
            return null;
        }
    }

public static void main(String []args){
     // 创建代理类
     ProductProxy proxy = new ProductProxy(new Product());
     //获取代理类实例Product
     Product product = (Product)(Proxy.newProxyInstance(Product.class.getClassLoader(), new Class[] {Product.class}, proxy)); 
     // 调用getPrice的函数,就会走到动态代理的invoke函数中
     product.getPrice();
}

通过动态代理,我们可以通过函数名来判断对应的函数以及对应操作,甚至于修改参数。

Retrofit中的动态代理

在Retrofit中,使用动态代理来对接口中的注释进行解析,解析后完成OkHttp的参数构建。

Retrofit的基本使用

首先来看一下使用Retrofit请求Github的的代码

  • 通过interface以及注释定义了该为Get请求,并且路径为/
public interface GitHubService {
        @GET("/")
        Call<GitHubApiBean> listGitHubApis();
}
  • 定义baseUrl为域名,并且添加GsonConverterFactory作为Response的转换工厂,创建Retrofit对象
String url = "https://api.github.com/";
Retrofit retrofit = new Retrofit.Builder()
       .baseUrl(url)//url必须以‘/’结尾
       .addConverterFactory(GsonConverterFactory.create())
       .build();
  • 调用函数,开始发起请求
//retrofit.create来生成一个接口实现类
GitHubService gitHubService=retrofit.create(GitHubService.class);
//调用指定方法
Call<GitHubApiBean> gitHubBeanCall=gitHubService.listGitHubApis();
//执行请求
gitHubBeanCall.enqueue(new Callback<GitHubApiBean>() {
     @Override
     public void onResponse(Call<GitHubApiBean> call, Response<GitHubApiBean> response) {
      String authorizations_url= response.body().getAuthorizations_url();
       String team_url= response.body().getTeam_url();
     }

    @Override
    public void onFailure(Call<GitHubApiBean> call, Throwable t) {
                Log.i("zfq", t.getMessage());
            }
    });

原理分析

在Retrofit的create中会通过Proxy.newProxyInstance来为传入的Service接口类创建一个代理对象,而当代理对象调用函数时,会调用动态代理的invoke函数。

public <T> T create(final Class<T> service) {
    ...
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
         
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            ...
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

而在invoke函数中,会通过调用loadServiceMethod函数,对Method中的注释进行解析,并且返回ServiceMethod对象,传入OkHttpCall中,构建OkHttp的请求。

public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
      // 通过注释中的Converter,创建Response中的转换器
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        // 解析注释中的GET/Post、Multipart等等
        parseMethodAnnotation(annotation);
      }
      ...  
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
               Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
      ...
    // 解析函数参数中的注释,例如Query,PartMap,FieldMap等
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ...
      return new ServiceMethod<>(this);
    }

Retrofit中的CallAdapter

CallAdapter的作用则是将请求中的数据进行转换,通过adapt函数进行转换,将A转换成B类型。

Retrofit.Builder test =new Retrofit.Builder().addCallAdapterFactory(new CallAdapter.Factory() {
            @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
                return new CallAdapter<Object, Object>() {
                    @Override public Type responseType() {
                        return null;
                    }

                    @Override public Object adapt(Call<Object> call) {
                        return null;
                    }
                };
            }
        });
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.05.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是代理
  • 什么是静态代理
  • 动态代理的背景
  • 动态代理
  • Retrofit中的动态代理
    • Retrofit的基本使用
    • 原理分析
    • Retrofit中的CallAdapter
    相关产品与服务
    腾讯云 BI
    腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档