这样和妻子解释:Java动态代理机制详解(JDK和CGLIB( 三 )
下面通过Javassist创建上述的Programmer类:
import javassist.ClassPool;import javassist.CtClass;import javassist.CtMethod;import javassist.CtNewMethod;public class MyGenerator {public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();//创建Programmer类CtClass cc= pool.makeClass("com.samples.Programmer");//定义code方法CtMethod method = CtNewMethod.make("public void code(){}", cc);//插入方法代码method.insertBefore("System.out.println(\"I'm a Programmer,Just Coding.....\");");cc.addMethod(method);//保存生成的字节码cc.writeFile("d://temp");}}
通过JD-gui反编译工具打开Programmer.class 可以看到以下代码:
文章插图
代理的基本构成:代理模式上 , 基本上有Subject角色 , RealSubject角色 , Proxy角色 。 其中:Subject角色负责定义RealSubject和Proxy角色应该实现的接口;RealSubject角色用来真正完成业务服务功能;Proxy角色负责将自身的Request请求 , 调用realsubject 对应的request功能来实现业务功能 , 自己不真正做业务 。
文章插图
上面的这幅代理结构图是典型的静态的代理模式:
当在代码阶段规定这种代理关系 , Proxy类通过编译器编译成class文件 , 当系统运行时 , 此class已经存在了 。 这种静态的代理模式固然在访问无法访问的资源 , 增强现有的接口业务功能方面有很大的优点 , 但是大量使用这种静态代理 , 会使我们系统内的类的规模增大 , 并且不易维护;并且由于Proxy和RealSubject的功能 本质上是相同的 , Proxy只是起到了中介的作用 , 这种代理在系统中的存在 , 导致系统结构比较臃肿和松散 。
为了解决这个问题 , 就有了动态地创建Proxy的想法:在运行状态中 , 需要代理的地方 , 根据Subject 和RealSubject , 动态地创建一个Proxy , 用完之后 , 就会销毁 , 这样就可以避免了Proxy 角色的class在系统中冗杂的问题了 。
下面以一个代理模式实例阐述这一问题:
将车站的售票服务抽象出一个接口TicketService,包含问询 , 卖票 , 退票功能 , 车站类Station实现了TicketService接口 , 车票代售点StationProxy则实现了代理角色的功能 , 类图如下所示 。
文章插图
对应的静态的代理模式代码如下所示:
package com.foo.proxy;/*** 售票服务接口实现类 , 车站* @author louluan*/public class Station implements TicketService {@Overridepublic void sellTicket() {System.out.println("\n\t售票.....\n");}@Overridepublic void inquire() {System.out.println("\n\t问询 。。。。 \n");}@Overridepublic void withdraw() {System.out.println("\n\t退票......\n");}}
package com.foo.proxy;/*** 售票服务接口* @author louluan*/public interface TicketService {//售票public void sellTicket();//问询public void inquire();//退票public void withdraw();}
文章插图
文章插图
package com.foo.proxy;/*** 车票代售点* @author louluan**/public class StationProxy implements TicketService {private Station station;public StationProxy(Station station){this.station = station;}@Overridepublic void sellTicket() {// 1.做真正业务前 , 提示信息this.showAlertInfo("××××您正在使用车票代售点进行购票 , 每张票将会收取5元手续费!××××");// 2.调用真实业务逻辑station.sellTicket();// 3.后处理this.takeHandlingFee();this.showAlertInfo("××××欢迎您的光临 , 再见!××××\n");}@Overridepublic void inquire() {// 1做真正业务前 , 提示信息this.showAlertInfo("××××欢迎光临本代售点 , 问询服务不会收取任何费用 , 本问询信息仅供参考 , 具体信息以车站真实数据为准!××××");// 2.调用真实逻辑station.inquire();// 3 。 后处理this.showAlertInfo("××××欢迎您的光临 , 再见!××××\n");}@Overridepublic void withdraw() {// 1 。 真正业务前处理this.showAlertInfo("××××欢迎光临本代售点 , 退票除了扣除票额的20%外 , 本代理处额外加收2元手续费!××××");// 2.调用真正业务逻辑station.withdraw();// 3.后处理this.takeHandlingFee();}/** 展示额外信息*/private void showAlertInfo(String info) {System.out.println(info);}/** 收取手续费*/private void takeHandlingFee() {System.out.println("收取手续费 , 打印发票 。。。。。 \n");}}
推荐阅读
- 程序员为教师妻子开发应用:将iPhone变成文档摄像头
- 三星Z Flip3可能就长这样了!副屏尺寸和镜头是亮点
- realme国潮锦鲤手机为什么叫V15?徐起解释命名规则
- “机器人妻子”上市遭抢购,是在解决刚需,还是在挑战伦理?
- 微软浏览器2021年迎重大版本:这样的Edge 88你喜欢吗
- 女子7千买新手机,不到2天就出问题了,售后:没法解释
- 中国这项技术领先世界,首次发起挑战,英国人:美国可不敢这样玩
- 雷军回应小米11标准版取消附送充电器:5年前我就有这样的困扰
- 三星屏下镜头机型专利曝光 这样的设计方案很完美
- 欧盟17国终于“出手了”!美国不愿看到这样的结果