这样和妻子解释:Java动态代理机制详解(JDK和CGLIB( 四 )
文章插图
由于我们现在不希望静态地有StationProxy类存在 , 希望在代码中 , 动态生成器二进制代码 , 加载进来 。 为此 , 使用Javassist开源框架 , 在代码中动态地生成StationProxy的字节码:
package com.foo.proxy;import java.lang.reflect.Constructor;import javassist.*;public class Test {public static void main(String[] args) throws Exception {createProxy();}/** 手动创建字节码*/private static void createProxy() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.makeClass("com.foo.proxy.StationProxy");//设置接口CtClass interface1 = pool.get("com.foo.proxy.TicketService");cc.setInterfaces(new CtClass[]{interface1});//设置FieldCtField field = CtField.make("private com.foo.proxy.Station station;", cc);cc.addField(field);CtClass stationClass = pool.get("com.foo.proxy.Station");CtClass[] arrays = new CtClass[]{stationClass};CtConstructor ctc = CtNewConstructor.make(arrays,null,CtNewConstructor.PASS_NONE,null,null, cc);//设置构造函数内部信息ctc.setBody("{this.station=$1;}");cc.addConstructor(ctc);//创建收取手续 takeHandlingFee方法CtMethod takeHandlingFee = CtMethod.make("private void takeHandlingFee() {}", cc);takeHandlingFee.setBody("System.out.println(\"收取手续费 , 打印发票 。。。。。 \");");cc.addMethod(takeHandlingFee);//创建showAlertInfo 方法CtMethod showInfo = CtMethod.make("private void showAlertInfo(String info) {}", cc);showInfo.setBody("System.out.println($1);");cc.addMethod(showInfo);//sellTicketCtMethod sellTicket = CtMethod.make("public void sellTicket(){}", cc);sellTicket.setBody("{this.showAlertInfo(\"××××您正在使用车票代售点进行购票 , 每张票将会收取5元手续费!××××\");"+ "station.sellTicket();"+ "this.takeHandlingFee();"+ "this.showAlertInfo(\"××××欢迎您的光临 , 再见!××××\");}");cc.addMethod(sellTicket);//添加inquire方法CtMethod inquire = CtMethod.make("public void inquire() {}", cc);inquire.setBody("{this.showAlertInfo(\"××××欢迎光临本代售点 , 问询服务不会收取任何费用 , 本问询信息仅供参考 , 具体信息以车站真实数据为准!××××\");"+ "station.inquire();"+ "this.showAlertInfo(\"××××欢迎您的光临 , 再见!××××\");}");cc.addMethod(inquire);//添加widthraw方法CtMethod withdraw = CtMethod.make("public void withdraw() {}", cc);withdraw.setBody("{this.showAlertInfo(\"××××欢迎光临本代售点 , 退票除了扣除票额的20%外 , 本代理处额外加收2元手续费!××××\");"+ "station.withdraw();"+ "this.takeHandlingFee();}");cc.addMethod(withdraw);//获取动态生成的classClass c = cc.toClass();//获取构造器Constructor constructor= c.getConstructor(Station.class);//通过构造器实例化TicketService o = (TicketService)constructor.newInstance(new Station());o.inquire();cc.writeFile("D://test");}}
上述代码执行过后 , 会产生StationProxy的字节码 , 并且用生成字节码加载如内存创建对象 , 调用inquire()方法 , 会得到以下结果:
文章插图
通过上面动态生成的代码 , 我们发现 , 其实现相当地麻烦在创造的过程中 , 含有太多的业务代码 。 我们使用上述创建Proxy代理类的方式的初衷是减少系统代码的冗杂度 , 但是上述做法却增加了在动态创建代理类过程中的复杂度:手动地创建了太多的业务代码 , 并且封装性也不够 , 完全不具有可拓展性和通用性 。 如果某个代理类的一些业务逻辑非常复杂 , 上述的动态创建代理的方式是非常不可取的!
- 程序员为教师妻子开发应用:将iPhone变成文档摄像头
- 三星Z Flip3可能就长这样了!副屏尺寸和镜头是亮点
- realme国潮锦鲤手机为什么叫V15?徐起解释命名规则
- “机器人妻子”上市遭抢购,是在解决刚需,还是在挑战伦理?
- 微软浏览器2021年迎重大版本:这样的Edge 88你喜欢吗
- 女子7千买新手机,不到2天就出问题了,售后:没法解释
- 中国这项技术领先世界,首次发起挑战,英国人:美国可不敢这样玩
- 雷军回应小米11标准版取消附送充电器:5年前我就有这样的困扰
- 三星屏下镜头机型专利曝光 这样的设计方案很完美
- 欧盟17国终于“出手了”!美国不愿看到这样的结果