Java的动态代理是学习Java的时候一个不好理解的知识点,本文将分享我在学习这个知识点中的笔记和理解。

Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。

Proxy提供用于创建动态代理类和代理对象的静态方法,也是所有动态代理类的父类。

如果我们在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态类;如果需要为一个或多个接口动态地创建实例,也可以使用Proxy来创建动态代理实例。

Proxy提供了如下两个方法来创建动态代理类和动态代理实例:

static Class<?>getProxyClass(ClassLoader loader,Class<?>… interfaces)

创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口,第一个ClassLoader指定生成动态代理类的类加载器。

static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandlerh)

直接创建一个动态代理对象,该代理对象的实现类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler对象的invoke方法。

实际上,采用第一种方式获取动态代理类之后,当程序需要通过该代理类来创建对象时一样需要传入一个InvocationHandler对象。也就是说,系统生成的每个代理对象都有一个与之关联的InvocationHandler对象。执行动态代理对象的每个方法时,都是执行InvocationHandler对象的invoke方法。

程序中生成动态代理对象可以先生成一个动态代理类,然后通过动态代理类来创建代理对象的方式来生成一个动态代理对象。

上面过程可以简化成下图的过程。

上面便是使用Java动态代理的一个基础,在贴demo代码之前,很多人学到了这里可能或多或少有一个困惑:我知道怎么去创建一个动态代理对象,不就是按这个流程去实现几个接口和类吗?可是又有什么用呢?自己new一个对象用不就行了吗?还代理来代理去的。确实,如果没有实际的应用场景,就很难体会到这样写的一个优势。

其实我们在平时做项目的时候可能会出现这样一个情况:一段代码可以在很多类里面重复使用。如果代码量少,重复的地方不多,那我们自然可以复制粘贴,如下所示的示意图。

示意图深色的部分就代表重复的部分。假如文件数量多的话,某一天需要对深色部分的代码修改,那意味着我们需要打开每一份源文件修改,显然维护这段代码的工作量将是巨大的。

有些经验的程序员可能会想到将这部分代码放在一个类的方法中,由其他代码调用即可,这样只要修改这一段代码,降低了维护的复杂度。但是这个时候这些调用这个方法的代码和这个方法又耦合了,这个时候动态代理的作用便体现出来了。

下面举一个例子。这里有一个Dog接口,里面定义了两个方法,然后用一个MyDog类实现这个接口。

public interface Dog {public void info();public void run();
}
public class MyDog implements Dog{​@Overridepublic void info() {System.out.println("我是狗蛋子");}
​@Overridepublic void run() {System.out.println("我跑的比**回快");}
}

现在要求在调用info()和run()方法时能够调用一个通用方法,但就像上面提到的,我们既不想用复制粘贴的方式实现,也不想通过硬编码的方式调用该方法。

public class DogUtil {public void method1(){System.out.println("111111111111111");}public void method2(){System.out.println("222222222222222");}
}

我们可以借助Proxy类和InvocationHandler接口实现,使程序调用info()方法和run()方法时,系统将自动把method1()和method2()两个方法插入到info()和run()方法中执行。

程序的关键在于写一个InvocationHandler实现类,该实现类的invoke方法将会作为代理对象的方法实现。

public class MyInvokationHandler implements InvocationHandler {//需要被代理的对象private Object target;public void setTarget(Object target){this.target=target;}//执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {DogUtil t = new DogUtil();t.method1();//通过反射以target作为主调来执行method方法//实现了调用target对象的原有方法Object result = method.invoke(target,args);t.method2();return result;}
}

然后我们定义一个MyProxyFactory类来为指定的target生成动态代理对象。

public class MyProxyfactory {//为指定target生成动态代理对象public static Object getProxy(Object target) throws Exception{//创建一个MyInvokationHandler对象MyInvokationHandler handler = new MyInvokationHandler();//为MyInvokationHandler设置target对象handler.setTarget(target);//创建并返回一个动态代理return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);}
}

这个类提供一个getProxy()方法,为target对象生成一个动态代理对象,这个对象与target实现了相同的接口,当程序调用动态代理对象的指定方法时,实际上将执行MyInvokationHandler对象的invoke方法,也就是说我们调用动态代理对象的方法时,程序的执行步骤为:

  • 创建DogUtil实例
  • 执行method1()方法
  • 使用反射以target作为调用者执行info()方法或者run()方法
  • 执行method2()方法

下面在主程序中测试一下。

public class Test {public static void main(String[] args) throws Exception{Dog target = new MyDog();Dog dog = (Dog)MyProxyfactory.getProxy(target);dog.info();dog.run();}
}

上面程序中的dog实际上是动态代理对象,只是它实现了Dog接口,所以也可以当成Dog对象使用。程序在执行dog的info()和run()之前会先执行DogUtil的method1(),然后再执行dog的info()和run(),最后执行DogUtil的method2()。测试结果如下。

我们可以看到动态代理很灵活的实现了解耦。当我们使用Proxy生成一个动态代理时,通常都是为指定的目标对象来生成动态代理,这种动态代理也被称为AOP代理,也是Spring中的一个重要内容。

Spring动态代理详解相关推荐

  1. JAVA动态代理详解

    JAVA动态代理详解 问题 1:什么是静态代理,动态代理? 2:动态代理的好处? 什么是静态代理 以生活中例子来看,我作为某某品牌面膜的北京区代理,我替厂家卖面膜,我属于代理,厂家属于委托方. 联系到 ...

  2. spring中aop默认使用jdk动态代理,springboot2以后默认使用cglib来实现动态代理详解

    Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...

  3. Spring之AOP动态代理详解

    动态代理 动态代理和静态代理角色一样 动态代理类是动态生成的,不是我们直接写好的. 动态代理分为两大类:基于接口的动态代理:JDK动态代理[我们在这里使用]基于类的动态代理:cglibjava字节码: ...

  4. Java 动态代理详解 ( 附示例源码,建议收藏)

    动态代理在Java中有着广泛的应用,比如Spring AOP.Hibernate数据查询.测试框架的后端mock.RPC远程调用.Java注解对象获取.日志.用户鉴权.全局性异常处理.性能监控,甚至事 ...

  5. java动态代理_Java代理模式及动态代理详解

    Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP.Java注解的获取.日志.用户鉴权等.本篇文章带大家了解一下代理模式.静态代理以及基于JDK原生动态代理. 代理模式 无 ...

  6. 为什么要用动态代理?静态代理与动态代理详解

    代理模式: 代理模式在Java中特别常见,如spring AOP功能就是用代理来实现的.代理模式作用是:在不修改被代理对象功能的基础上,通过对代理类进行扩展,进行一些功能上的附加与增强. 一般使用代理 ...

  7. Java中的动态代理详解

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

  8. 静态代理,JDK动态代理,Cglib动态代理详解

    目录 一.代理模式 二.静态代理 三.动态代理 3.1 JDK动态代理 3.2 Cglib动态代理 四.两种动态代理区别 一.代理模式 代理模式(Proxy Pattern)是程序设计中的一种设计模式 ...

  9. Java代理模式及动态代理详解

    本文转自:程序新视界公众号 Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP.Java注解的获取.日志.用户鉴权等.本篇文章带大家了解一下代理模式.静态代理以及基于JDK ...

  10. java类加载机制、反射、动态代理详解

    类的加载.连接和初始化(系统可能在第一次使用某个类时加载该类, 也可能采用预加载机制来加载某个类)动态代理实现 1.JVM和类 当调用 java 命令运行某个 Java 程序时, 该命令将会启动一个 ...

最新文章

  1. P4269 [USACO18FEB]Snow Boots G
  2. JAVE SE 学习day_09:sleep线程阻塞方法、守护线程、join协调线程同步方法、synchronized关键字解决多线程并发安全问题
  3. JSR311发布Restful WebService工程
  4. ORACLE REDO 日志调整
  5. MyBatis从入门到精通:update用法、delete用法
  6. MySQL 5.5 主从复制异步、半同步以及注意事项详解
  7. oracle out参数查询,Oracle的out参数实例详解
  8. Linux快速查找库文件位置
  9. python运行系统_python执行系统命令的方法
  10. 元年深度 | 侧袋机制应用实务探讨
  11. 《王道计算机考研》:应用层
  12. 中科院计算所培训中心新一期javascript培训结束
  13. linux下安装杰奇2.4,实现关关采集器远程采集详细教程
  14. python如何打开文件选择框_python文件选择对话框的操作方法
  15. ISBN编号的国家地区语言代码,出版社代码规则,中国出版社ISBN代码
  16. 百度公司关于SEO的建议
  17. java 时分秒 转换 秒_【Java】 秒转时分秒天
  18. Vue - 判断终端是否为:IE内核、opera内核、苹果、谷歌内核、火狐内核、是否为移动终端、ios终端、android终端、是否为iPhone或者QQHD浏览器、是否iPad、是否微信、是否QQ
  19. 方舟服务器建家位置,方舟生存进化新手建家图文攻略 方舟生存进化在哪建家比较好-游侠网...
  20. 用米思齐mixly和APP INVENTOR 2通过MQTT控制灯亮和熄

热门文章

  1. 正确获取CleanMyMac注册码并激活
  2. win 10 使用技巧总结
  3. linux修改文件权限为所有人都可以访问,Linux 笔记分享八:文件权限的设定
  4. java 数据库基础_数据库基础知识考试及答案 PDF 下载
  5. 基于 Java 机器学习自学笔记 (第66至68天:主动学习之ALEC)
  6. matlab获取全局变量的值_全局变量在几个函数及Matlab函数中都能使用的变量.PPT...
  7. Linux 代码美化(二)
  8. 简约个性个人简历自我介绍PPT模板
  9. 如何进行业务需求分析
  10. 【测试人生】安卓FPS测试详解