博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
代理模式分类
阅读量:6159 次
发布时间:2019-06-21

本文共 5084 字,大约阅读时间需要 16 分钟。

一、代理概念

  代理的两种模式静态代理和动态代理,这个是怎么区别的我们谈一下,Java中都是通过编译器生成.class文件,在通过JVM读取,

然后加载到内存中,生成对应的需要对象,根据代理类创建的时间分成静态和动态代理,静态的代理就是在程序运行前.class文件就存在,
我们经常使用的代理模式就是静态代理,动态代理就是程序运行时动态创建,比如JDK的动态代理和CGLB代理;

二、静态代理----代理模式

   这里我们使用取款机这个例子来说一下,现在假如说你是招商的银行卡,你需要在工商取款机取款,这里有个规定那就是每笔需要收费2元,这个工商取款机就是代理对象,你的目标对象就是取款,我们抽象一个取款的接口WithdrawService,招商取款机上面的实现取款机接口ATM,然后工商取款机ATMProxy实现代理角色;当然这里我简化很多步骤;

1 /** 2  * 抽象的取款接口 3  */ 4 public interface WithdrawService { 5     int GetByMoneyWithdraw(int money); 6 } 7  8 /** 9  * ATM机实现的接口10  */11 public class ATM implements WithdrawService{12     @Override13     public int GetByMoneyWithdraw(int money) {14         System.out.print("取款"+money);15         return money;16     }17 }18 19 /**20  * 代理对象21  */22 public class ATMProxy implements WithdrawService {23     private ATM atm;24     public ATMProxy(ATM atm){25         this.atm=atm;26     }27     @Override28     public int GetByMoneyWithdraw(int money) {29 30         int proxyMoney=2;31         System.out.print("取款"+money+":"+"手续费"+proxyMoney);32         atm.GetByMoneyWithdraw(money+proxyMoney);33         return money+proxyMoney;34     }35 }36 /**37  * 测试类38  */39 public class ProxyTest {40     public static void main(String[] args){41         WithdrawService withdrawService=new ATMProxy(new ATM());42         withdrawService.GetByMoneyWithdraw(1000);43     }44 }

以上就是静态代理,在运行前就生成,代理模式的优点就在于不直接依赖于目标对象,而是通过代理对象作为中间对象也就是我们经常说的解耦;另外代理对象还可以对实现的方法进行增强,增加自己的规则,这里我们思考一个问题:当我们每增加一个代理类的时候,我就需要编写一个类,这样我们代码通用很差,另外这样子会照成系统更加复杂,执行速度更加慢;这就背离了我们设计的原则,那么怎么避免这种问题?

三、动态代理----JDK动态代理

   针对于上面提出的问题,通过反射机制,JDK给我们提供Proxy类,这个只是针对于接口的增强,在JVM运行时动态创建生成。这里简单说一下JDK通过接口动态生成代理对象的过程:

    1.获取WithdrawService接口下所有方法;

    2.生成代理类,默认为命名空间+$+Proxy+类名;

    3.根据接口,在代码中动态创建代理的字节码文件;

    4.将字节码文件转化为class文件;

    5.创建InvocationHandler实例handler,来处理代理的方法调用

    6.Proxy的class对象以创建的handler对象为参数,实例一个proxy对象;

   下面我们展示一下JDK实现代理:

1 /** 2  * 抽象的取款接口 3  */ 4 public interface WithdrawService { 5     int GetByMoneyWithdraw(int money); 6 } 7  8 /** 9  * ATM机实现的接口10  */11 public class ATM implements WithdrawService{12     @Override13     public int GetByMoneyWithdraw(int money) {14         System.out.print("取款"+money);15         return money;16     }17 }18 19 /**20  * JDK动态代理的实现21  */22 public class ATMJDKProxy implements InvocationHandler {23     //目标对象24     private Object target;25     //构建目标对象26     public ATMJDKProxy(Object target){27         super();28         this.target=target;29     }30     //获取目标的代理对象31     public Object getProxy(){32         return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),this.target.getClass().getInterfaces(),this);33     }34     @Override35     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {36         System.out.print("执行前处理什么事情");37         Object result = method.invoke(target, args);38         System.out.print("执行后处理什么事情");39         return result;40     }41 }42 43 /**44  * 测试类45  */46 public class ProxyTest {47 48     public static void main(String[] args) {49         WithdrawService withdrawService=new ATM();50         ATMJDKProxy atmjdkProxy=new ATMJDKProxy(withdrawService);51         WithdrawService proy= (WithdrawService) atmjdkProxy.getProxy();52         proy.GetByMoneyWithdraw(1000);53     }54 }

四、动态代理----CGLIB动态代理 

   JDK动态代理只能实现对接口方法的增强,不能实现对接口类的的动态代理。那么我们想动态生成类的时候怎么办,不用想了那就是使用CGLIB类库;这个当然也是在JVM运行时动态创建,这里也简单描述下生成ATM动态代理类的过程:

   1.查找ATM类中的非final的public类型方法;

   2.将这些方法定义转化为字节码;

   3.将组成字节码转化为代理的Clss类;

   4.实现MethodInterceptor 接口,用来处理代理方法上的请求;

   下面我们展示一下CGLIB实现代理:

1 /** 2  * ATM不实现接口 3  */ 4 public class ATM { 5     public int GetByMoneyWithdraw(int money) { 6         System.out.print("取款"+money); 7         return money; 8     } 9 }10 11 /**12  * 实现MethodInterceptor13  */14 public class ATMCGLIBProxy implements MethodInterceptor {15     private Object target;16     public Object getInstance(Object target){17         this.target=target;18         Enhancer enhancer=new Enhancer();19         enhancer.setSuperclass(this.target.getClass());20         enhancer.setCallback(this);21         return enhancer.create();22     }23     @Override24     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {25         System.out.println("开始前");26         methodProxy.invokeSuper(o,objects);27         System.out.println("开始后");28         return null;29     }30 }31 /**32  * 测试类33  */34 public class ProxyTest {35 36       public static void main(String[] args) {37           ATMCGLIBProxy cglib=new ATMCGLIBProxy();38           ATM atm = (ATM) cglib.getInstance(new ATM());39           atm.GetByMoneyWithdraw(1000);40       }41 }

以上是基本实现,这里我们简单说一下CGLIB底层是通过使用字节码处理框架ASM,来转换字节码并生成新的类;什么是ASM?ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

   这里需要注意使用这个的时候需要引入:cglib-nodep-2.2.jar;cglib-2.2.jar;asm-3.2jar;

 五、动态代理----应用场景

  大家执行过上面的代码以后会有一种是曾相识的感觉,在方法执行前做一些事,在方法执行后做一些事,使我们很容易想到Spring Aop中的通知,这里确实有用到动态代理,至于别的我暂时还没有想到,等等那天解读Spring源码的时候我们再来探讨一下,到此结束;

 

转载地址:http://znafa.baihongyu.com/

你可能感兴趣的文章
虚机不能启动的特例思考
查看>>
SQL Server编程系列(1):SMO介绍
查看>>
在VMware网络测试“专用VLAN”功能
查看>>
使用Formik轻松开发更高质量的React表单(三)<Formik />解析
查看>>
也问腾讯:你把用户放在什么位置?
查看>>
CSS Sprites 样式生成工具(bg2css)
查看>>
[转]如何重构代码--重构计划
查看>>
类中如何对list泛型做访问器??
查看>>
C++解析XML--使用CMarkup类解析XML
查看>>
P2P应用层组播
查看>>
Sharepoint学习笔记—修改SharePoint的Timeouts (Execution Timeout)
查看>>
CSS引入的方式有哪些? link和@import的区别?
查看>>
Redis 介绍2——常见基本类型
查看>>
asp.net开发mysql注意事项
查看>>
(转)Cortex-M3 (NXP LPC1788)之EEPROM存储器
查看>>
ubuntu set defult jdk
查看>>
[译]ECMAScript.next:TC39 2012年9月会议总结
查看>>
【Xcode】编辑与调试
查看>>
用tar和split将文件分包压缩
查看>>
[BTS] Could not find stored procedure 'mp_sap_check_tid'
查看>>