目录

初衷

动态代理

实例讲解

总结


初衷

在研究Retrofit源码中,在创建网络请求接口实例时,就是通过Java动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给了InvocationHandler来具体生成对应平台的代理对象。对应的代码如下:

public <T> T create(final Class<T> service) {//。。。。代码省略return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {private final Platform platform = Platform.get();@Override public Object invoke(Object proxy, Method method, Object... args)throws Throwable {//。。。。代码省略return serviceMethod.callAdapter.adapt(okHttpCall);}});}

其中使用Proxy.newProxyInstance来创建了一个代理类实例,那么对应的这个InvocationHandler怎么用呢?这个动态代理到底是怎么回事呢?研究下

动态代理

  • 基本概念

代理类在程序运行时创建的代理方式。与静态代理的区别在于静态代理的代理类是编译之前就存在了,像AIDL服务,其中的代理类在我们运行服务之前就借助Android Studio自动生成。

  • 优点

动态代理用于在编译的时候无法知道,只有在运行的时候才知道。像在Retrofit中创建网络请求接口的时候,并不知道是Android、iOS或者Java在使用,所以就需要设置CallAdapter来将设置的网络请求接口转换成对应平台的Http请求。这样开发者不需要手动去做适配,直接通过动态代理就可以完成这个适配过程。

优点在于可以对代理类的所有方法统一处理,不需要单独修改

1)InvocationHandler

可以理解为监听接口的方法的调用,可以在方法调用的时候,追加一些其他操作,查看源码如下

public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

我们发现其中里面有三个参数

对应的参数 参数对应的含义
proxy 调用方法的代理实例
method 代理实例上调用的接口方法,包括若有父类,父类中声明的接口方法
args 传入代理实例上调用的接口方法的参数
返回值 就是上述的method的返回值。如果是基本数据类型,则返回的是其包装类的类型

2)Proxy.newProxyInstance

动态生成给定接口的代理类。注意这里仅仅只针对接口类。

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

其中三个参数的含义如下:

对应的参数 参数对应的含义
loader 用来去加载代理对象的类加载器
interfaces 动态代理类需要实现的接口集合
h 可以理解为监听动态代理方法的调用。
返回值 根据上面三个参数生成的代理实例

实例讲解

我们定义了一种X付宝的支付方式,需要在支付方法在调用前增加安全校验和在支付结束增加支付成功的提示。那么在不修改原X付宝的支付方法的前提下,利用动态代理来实现该功能。

  • 定义支付接口
public interface Pay {Pay pay();
}

注意这里的方法的返回值要保持一致,否则在InvocationHandler的invoke()的返回值的要注意处理不同。

  • 定义X付宝支付方式
public class XliPay implements Pay {@Overridepublic Pay pay() {System.out.println("正在使用X付宝支付");return this;}
}
  • 创建一个XliPay的代理类,在invoke方法的时候增加我们的校验检查
public class PayAccount<T> {public void before() {System.out.println("代理中。。。。检查支付方式是否安全。。。。");}public void after() {System.out.println("代理中。。。。成功完成支付。。。。。");}public T create(final Class<T> serviceInterface, final Class<XliPay> proxyInstance) {return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object obj = method.invoke(proxyInstance.getConstructor().newInstance(), args);after();return obj;}});}
}
  • 运行执行pay()看结果
  public static void main(String[] args) {PayAccount<Pay> payPayAccount = new PayAccount<>();Pay pay = payPayAccount.create(Pay.class, XliPay.class);pay.pay();
}

查看结果如下:

代理中。。。。检查支付方式是否安全。。。。
正在使用X付宝支付
代理中。。。。成功完成支付。。。。。

这样就可以直接在不用修改XliPay的pay()就完成了我们想要的效果。并且我们可以任意调整这几个方法的调用顺序。

总结

动态代理就是在调用委托类的方法的时候,可以在改变原有类的情况下,动态去替换原来的实现方法或者对其进行扩展。

但是动态代理最根本的就是利用了java的反射,所以对效率上是有一点点影响的。

Java动态代理InvocationHandler的一点感悟相关推荐

  1. Java动态代理InvocationHandler和Proxy学习笔记

    java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心: 1.Inv ...

  2. 【Java动态代理】—— 每天一点小知识

  3. java 动态代理深度学习(Proxy,InvocationHandler)

    http://hi.baidu.com/malecu/item/9e0edc115cb597a1feded5a0 http://www.iteye.com/topic/683613 http://bl ...

  4. java 动态代理范例 InvocationHandler与Proxy

    java 动态代理范例 InvocationHandler与Proxy,拦截与代理 java.lang.reflect.Proxy, Proxy 提供用于创建动态代理类和实例的静态方法. newPro ...

  5. java动态代理三座大山InvocationHandler、newProxyInstance()和invoke()

    先分享记录些博主的文章: <SSM框架>2Spring详解-KuangStudy-文章 java动态代理Proxy.newProxyInstance_徐海兴的专栏-CSDN博客_proxy ...

  6. java动态代理【一】

    java动态代理的定义:为其他目标类的方法增加切面的逻辑,即在执行目标类方法的时候,先去执行一段如校验检测的逻辑代码.java通俗一点就是生成一个继承目标类的子类,并在每个调用方法都添加一段逻辑. 应 ...

  7. Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  8. Java 动态代理机制分析及扩展--转

    http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...

  9. Java 动态代理机制分析及扩展,第 1 部分

    引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...

最新文章

  1. Scrum敏捷开发工具分享
  2. python连接elasticsearch查询数据
  3. JS 设计模式 四(单例)
  4. 使用log4j2免费分配日志记录
  5. mysql 优化 案例_[MySQL优化案例]系列 -- OPTIMIZE的威力
  6. MySQL表名后接t_mysql表名忽略大小写
  7. python必背代码-Python一些实用代码
  8. (转)iOS 屏幕适配
  9. 【对话】对话系统经典:检索式对话
  10. 【VS开发】ConvertBSTRToString(filename) 不能将string转换为BSTR
  11. 华为手机打开日志输出的几种方法
  12. ssm房屋租赁管理系统ssm房屋管理系统JSP网上租房系统JSP房产信息网站房屋租赁系统房屋
  13. 有限域f9的特征是多少_密码学数学基本第十一讲有限域.ppt
  14. php位运算符与逻辑运算_php 或_php 逻辑运算符和
  15. Eclipse美化操作
  16. Android CPU架构之ARM和X86
  17. 抖音只能上下滑动吗_仿抖音上下滑动分页视频
  18. 中国有史以来最缠绵词章大盘点
  19. 海康威视的视频如何显示在web页面上显示
  20. Camtasia2023最好用的电脑屏幕录制软件

热门文章

  1. 89 岁教授起诉知网获赔 70 万:自己的论文竟要花钱才能看?央视网评上热搜:不问自取即为盗
  2. 转换矩阵 Matrix详解
  3. 字节跳动笔试题2020 (抖音电商)
  4. 【学习笔记62】判断数据类型的方法
  5. 老闪创业那些事儿(64)——为什么面试不通过?
  6. 面向对象编程-鸵鸟到底是不是鸟?企鹅是不是鸟?
  7. electron集成arm64架构的nodejs addon插件
  8. 云管理平台:9大开源云管理平台(CMP)
  9. 自我介绍的第一个帖子鸭
  10. EXCHANGE 完全访问权限邮箱的设置