根据前面介绍的Proxy和InvocationHandler,实在很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制.

只要我们开发一个实际使用的软件系统,总会出现相同代码重复出现的情形,在这种情形下,最常见的做法是:选中那些代码一路“复制”、“粘贴”立即实现系统的功能,如果仅仅从软件功能上来看,他们确实已经完成了软件的开发。对于采用上述方法实现的系统,在软件开发期间可能会觉得无所谓,但如果有一天需要修改程序的公共部分,那意味着打开多份源代码进行修改。如果有100个地方,甚至是1000个地方使用了这段深色代码段,那修改维护这段代码的工作量将变成噩梦。

在这种情况下大部分少有经验的开发这都会将公共代码块定义成一个方法,然后让另外三段代码块直接调用该方法即可。这时如果需要修改公共的代码则只需要修改一次即可。而调用该方法的代码段,不管有多少地方调用了该方法,完全无须任何修改。只要被调用方法被修改了,所有调用该方法的地方自然改变了,通过这种方式大大降低了软件后期维护的复杂度。

但是这种方式最大的问题就是每个调用公共代码块的部分都和公共代码块有耦合,不利于调试和测试。最理想的效果就是公共的代码块既被执行又无须再程序中以硬编码方式直接被调用,这时候就可以通过动态代理的方式来达到这种效果。

由于JDK的动态代理只能创建指定接口的动态代理,所以下面先提供一个Dog接口,该接口代码非常简单,仅仅在该接口里定义了两个方法

interface Dog {// info()方法声明public void info();// run()方法声明public void run();
}

上面接口里只是简单定义了两个方法,并未提供方法实现。如果我们直接使用Proxy为该接口创建动态代理对象,则动态代理对象的所有方法的执行效果又将完全一样。在这种情况下,我们将先为该Dog接口提供一个简单的实现类:GunDog

class GunDog implements Dog {// info方法实现,仅仅打印一个字符串@Overridepublic void info() {System.out.println("我是一只猎狗");}// run方法实现,仅仅打印一个字符串@Overridepublic void run() {System.out.println("我奔跑迅速");}
}

上面代码没有丝毫的特别之处,该Dog的实现类仅仅为每个方法提供了一个简单实现。回到开始我们需要实现的功能:让公用的代码不以硬编码的方式出现在需要调用他的类中。此时我们假设info(),run()两个方法代表要调用公共代码的方法,那么要求:程序执行info(),run()方法时能调用某个通用的方法,但又不通过硬编码的方式调用该方法。下面提供DogUtil类该类中包含两个通用的方法。

class DogUtil {// 第一个拦截器方法public void method1() {System.out.println("-----------模拟第一个通用方法-----------");}// 第二个拦截器方法public void method2() {System.out.println("-----------模拟第二个通用方法-----------");}
}

借助于Proxy和InvocationHandler就可以实现:当程序调用info()方法和run()方法时,系统可以“自动”将method1()和method2()两个通用方法插入info()和run()方法执行中。

这个程序的关键在于下面的MyInvokationHandler类,该类是一个InvovationHandler实现类,该实现类的invoke方法将会作为代理的方法实现。

class MyInvokationHandlerPro implements InvocationHandler {// 需要被代理的对象private Object target;public void setTarget(Object target) {this.target = target;}// 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法public Object invoke(Object proxy, Method method, Object[] args)throws Exception {DogUtil du = new DogUtil();// 执行DogUtil对象中method1方法du.method1();// 以target作为主调来执行method方法Object result = method.invoke(target, args);// 执行DogUtil对象中method2方法du.method2();return result;}
}

上面程序实现了invoke方法时包含了一行关键代码,这行代码通过反射以target作为主调来执行method方法,这就是实现了调用target对象的原有方法。在粗体字代码之前调用DogUtil对象的method1()方法,在其后调用DogUtil对象的method2()方法。

下面为程序提供一个MyProxyFactory类,该对象专为指定的target生成动态代理实例。

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

上面动态代理工厂类提供了一个getProxy方法,该方法为target对象生成一个动态代理对象,这个动态代理对象与target实现了相同的接口,所以具有相同的public方法,从这个意义上来看,动态代理对象可以当成target对象使用。当程序调用动态代理对象的指定方法时,实际上将变成执行MyInvokationHandler对象的invoke方法。例如调用动态代理对象的info()方法,程序将开始执行invoke方法,其执行步骤如下

1、创建DogUtil实例

2、执行DogUtil实例的method1()方法。

3、使用反射以target作为调用者执行info()方法。

4、执行DogUtil实例的method2()方法。

看到上面执行的过程,读者应该已经发现:当我们使用动态代理对象代替target对象时,代理对象的方法就实现类前面的要求:程序执行info()、

run()方法时能调用method1()、method2()通用方法,但GunDog的方法中又没有以硬编码的方式调用method1()和method2()。

下面提供主程序来测试这种动态代理的效果

public class TestProxy {public static void main(String[] args) throws Exception {// 创建一个原始的GunDog对象,作为targetDog target = new GunDog();// 以指定的target来创建动态代理Dog dog = (Dog) MyProxyFactory.getProxy(target);dog.info();dog.run();}
}

上面程序中dog对象实际上是动态代理对象,只是该动态代理对象也实现类Dog接口,所以也可以当成Dog对象使用。程序执行dog的info()和run()方法时,实际上会先执行DogUtil的method1()在执行target对象的info()和run()方法最后在执行DogUtil的method2()执行结果如下图所示

通过上图来看不难发现采用动态代理可以非常灵活的实现解耦。通常而言,当我们使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的实际意义。通常都是为指定的目标对象来生成动态代理。

这种动态代理在AOP(Aspect Orient Program,面向切面编程)里被称为AOP代理,AOP代理可替代目标对象,AOP代理包含了目标对象的全部发那个发。但AOP代理中的方法与目标对象的方法存在差异:AOP代理里的方法可以在执行目标方法之前,之后插入一些通用处理。

转载于:https://www.cnblogs.com/beijiguangyong/archive/2013/02/28/2966595.html

动态代理(2)----动态代理和AOP相关推荐

  1. 代理模式——静态代理,动态代理(JDK代理和CGLib代理)

    概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问. 这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. Java中的代理按照代理类生成时机不同又分为 ...

  2. JAVA 进阶篇 动态代理 JDK动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理 JDK动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. CGlib动态代理: 利用ASM(开源的Java ...

  3. Java两种动态代理JDK动态代理和CGLIB动态代理

    目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...

  4. 代理模式之详谈动态代理模式(Spring的AOP实现)

    java动态代理实现与原理详细分析 1.代理模式 关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 代理 ...

  5. 动态代理——拦截器——责任链——AOP面向切面编程底层原理详解(迪丽热巴版)

    目录 动态代理模式详解 前言 什么是代理模式 如何进行代理 静态代理 动态代理 JDK动态代理 CGLIB动态代理 拦截器 责任链模式 博客文章版权申明 动态代理模式详解 前言 代理模式是设计模式中非 ...

  6. 动态代理及JDK代理源码解析

    动态代理及JDK代理源码解析 参考:JDK动态代理-超详细源码分析 - 简书 (jianshu.com) 文章目录 动态代理及JDK代理源码解析 一.为什么需要动态代理 什么是代理模式? 静态代理: ...

  7. Java设计模式(五)代理设计模式—静态代理—JDK动态代理—Cglib动态代理

    文章目录 什么是代理模式 代理模式应用场景 代理的分类 静态代理 什么是静态代理 深入解析静态代理 小结 动态代理 什么是动态代理 JDK动态代理 原理和实现方式 代码实现 优缺点 Cglib动态代理 ...

  8. 动态代理——CGLIB动态代理原理示例解析

    觉得可以的话点个关注,转个发呗,陆续奉上干货~~~~ 前文我们讲解了JDK动态代理的原理(动态代理--JDK动态代理原理),今天我们来看看CGLIB动态代理是如何实现,最后我们总结下JDK动态代理和C ...

  9. Android开发如何理解Java静态代理 动态代理及动态生成代理对象原理 看这篇就够了

    动态代理与静态代理 前言 代理模式 静态代理 动态代理 JDK代理 动态生成代理对象原理 生成class数据源码 动态代理类真身 总结 前言 近期在研究Hook技术,需要用到动态代理,说到动态代理就会 ...

  10. 什么是动态代理?动态代理有哪些应用?如何编写动态代理案例

    什么是动态代理? 当我们需要给某个类或者接口中的方法添加一些额外的功能比如日志.事务的时候,可以通过创建一个代理类来实现这些功能:该代理类既包含了原有类的完整功能,同时在这些功能的基础上添加了其他的逻 ...

最新文章

  1. JVM中线程是否可以并行执行
  2. 跑yolo3模型出的效果图_效果图和效果图设计到底有什么区别?区别大着呢,亲……...
  3. 查看SSID的mac地址
  4. Windows下LATEX排版论文攻略—CTeX、JabRef使用心得
  5. python selenium 鼠标移动到指定元素,并点击对应的元素
  6. koa2 session mysql_koa2实现session的两种方式(基于Redis 和MySQL)
  7. 基于wordpress搭建网站和基于nodejs自己搭建
  8. 视频流传输协议RTP/RTCP/RTSP/HTTP的区别
  9. CSS3构建一个正方体
  10. 当当网商品详情API接口(当当商品详情接口,当当商品问答接口,当当抢购价接口,当当商品列表接口,当当商品评论接口)代码对接教程
  11. Spring Cloud之赵国的覆灭
  12. ucore源码分析step1
  13. 强劲的网络。http://www.chartboost.com/
  14. Jquery Jqprint—随着Jquery Jqprint实现网页打印
  15. 渗透学什么?渗透测试中超全的提权思路来了!
  16. Redis客户端常用命令大全
  17. 初学订单-支付流程(思路)
  18. vue之vue的生命周期、swiper、自定义组件的封装、自定义指令、过滤器、单文件组件及vue-cli
  19. linux 创建分区 4t,centos对4T硬盘进行分区
  20. BES(恒玄)蓝牙平台EQ 调试和设定

热门文章

  1. 计算机专业英语问卷调查,调查问卷英文版.doc
  2. 让你“爱”上 GitHub,解决访问时图裂、加载慢的问题
  3. php监考,科学网—监考与被监考 - 张珑的博文
  4. Cocos2dx 之 ButtonSprite
  5. Fixchart图表组件——介绍
  6. glPushMatrix()和glPopMatrix()以及glLoadIdentity()的理解
  7. 凸函数、凸规划的定义及学习
  8. ORA-00054 resource busy and acquire with NOWAIT specified Cause 错误解决方法
  9. 前端性能优化的那些事
  10. (转)JAVA泛型通配符T,E,K,V区别,T以及Class,Class的区别