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

Java动态代理InvocationHandler和Proxy学习笔记1 InvocationHa 接口是 proxy 代理实例的调用处理程序实现的一个接口 每一个 proxy 代理实例都有一个关联的调用处理程序 在代理实例调用方法时 方法调用被编码分派到调用处理程序的 invoke 方法 看下官方文档对 InvocationHa 接口的描述 codeInvocati istheinterfa

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

1.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

看下官方文档对InvocationHandler接口的描述:

 {@code InvocationHandler} is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the {@code invoke} method of its invocation handler.

每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:

 / * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 * method:我们所要调用某个对象真实的方法的Method对象 * args:指代代理对象方法传递的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
2.Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。
 public static Object newProxyInstance(ClassLoader loader, Class 
  [] interfaces, InvocationHandler h)
 Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. This method is equivalent to:

这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:

  • loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
  • interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
  • h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
3动态代理中核心的两个接口和类上面已经介绍完了,接下来我们就用实例来讲解下具体的用法
  • 首先我们定义一个接口People
package reflect; public interface People { public String work(); }
  • 定义一个Teacher类,实现People接口,这个类是真实的对象
package reflect; public class Teacher implements People{ 
    @Override public String work() { System.out.println("老师教书育人..."); return "教书"; } } 
  • 现在我们要定义一个代理类的调用处理程序,每个代理类的调用处理程序都必须实现InvocationHandler接口,代理类如下:
package reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class WorkHandler implements InvocationHandler{ 
    //代理类中的真实对象  private Object obj; public WorkHandler() { // TODO Auto-generated constructor stub } //构造函数,给我们的真实对象赋值 public WorkHandler(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在真实的对象执行之前我们可以添加自己的操作 System.out.println("before invoke。。。"); Object invoke = method.invoke(obj, args); //在真实的对象执行之后我们可以添加自己的操作 System.out.println("after invoke。。。"); return invoke; } } 

上面的代理类的调用处理程序的invoke方法中的第一个参数proxy好像我们从来没有用过,而且关于这个参数的具体用法含义请参考我的另外一篇文章Java中InvocationHandler接口中第一个参数proxy详解

  • 接下来我们看下客户端类
package reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Test { 
    public static void main(String[] args) { //要代理的真实对象 People people = new Teacher(); //代理对象的调用处理程序,我们将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法 InvocationHandler handler = new WorkHandler(people); / * 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数 * 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象 * 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法 * 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上 */ People proxy = (People)Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler); //System.out.println(proxy.toString()); System.out.println(proxy.work()); } } 

看下输出结果:

before invoke。。。 老师教书育人... after invoke。。。 教书

通过上面的讲解和示例动态代理的原理及使用方法,在Spring中的两大核心IOC和AOP中的AOP(面向切面编程)的思想就是动态代理,在代理类的前面和后面加上不同的切面组成面向切面编程。

上面我们只讲解了Proxy中的newProxyInstance(生成代理类的方法),但是它还有其它的几个方法,我们下面就介绍一下:

  • getInvocationHandler:返回指定代理实例的调用处理程序
  • getProxyClass:给定类加载器和接口数组的代理类的java.lang.Class对象。
  • isProxyClass:当且仅当使用getProxyClass方法或newProxyInstance方法将指定的类动态生成为代理类时,才返回true。
  • newProxyInstance:返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202850.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午11:09
下一篇 2026年3月19日 下午11:09


相关推荐

  • 外键(FOREIGN KEY)

    外键(FOREIGN KEY)引子:把所有数据都存放于一张表的弊端  1、表的组织结构复杂不清晰  2、浪费空间  3、扩展性极差为了解决上述的问题,就需要用多张表来存放数据。表与表的记录之间存在着三种关系:一对多、多对多、一对一的关系。处理表之间关系问题就会利用到FOREIGNKEY多对一关系:寻找表与表之间的关系的套路  举例:雇员表:emp表  部门:dep表    part1:    …

    2022年6月29日
    30
  • 常见函数的泰勒公式展开_基本泰勒公式展开表

    常见函数的泰勒公式展开_基本泰勒公式展开表笔记

    2025年7月2日
    8
  • sqlpro studio 2021激活码[最新免费获取]

    (sqlpro studio 2021激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1STL5S9V8F-eyJsaWN…

    2022年3月27日
    251
  • 高效的NoSQL数据库服务Amozon DynamoDB体验分享

    高效的NoSQL数据库服务Amozon DynamoDB体验分享AmazonDynamo 是一种全托管 NoSQL 数据库服务 相当于在 NoSQL 的基础上做了很多扩展 附加了很多降本增效的功能 让开发人员不需要额外去维护什么 开箱即用 它主要提供的服务有 无缝扩展 快速可预测的性能 减少繁琐的管理分布式数据库的工作负担 提供静态加密 按需备份 自动维护过期项目等 极大的减少开发人员的时间成本和提高建设效率

    2026年3月19日
    3
  • redux-saga_pub culture

    redux-saga_pub culture本文用以记录从调研ReduxSaga,到应用到项目中的一些收获。什么是ReduxSaga官网解释来自:https://github.com/redux-saga/redux-sagaredux-sagaisalibrarythataimstomakesideeffects(i.e.asynchronousthingslikedatafetchingand…

    2026年1月27日
    4
  • ipsec iptables_iptables -p

    ipsec iptables_iptables -piptablesiptables[-t表名]命令选项[链名][条件匹配][-j目标动作或跳转]-t表名可以省略,指定规则存放在哪个表中,默认为filter表用于存放相同功能的规则filter表:负责过滤功能能,nat表:网络地址转换功能mangle表:拆解报文做出修改并重新封装的功能raw表:关闭nat表上启用的连接追踪机制命令选项-A在…

    2022年10月7日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号