当前位置:首页 > 每日看点 > 正文内容

请问jdk,cgli,jassist和A有什么区别吗?

卡卷网12个月前 (01-10)每日看点161

好的,我来详细解释每种方式的实现原理和代码示例。

JDK

    核心是通过实现InvocationHandler接口使用Proxy.newProxyInstance创建对象只能实现了接口的类

//目标接口 pulicinteceUserServ{ voidaddUser(Stringname); } //目标类 pulicclassUserServImplimplementsUserServ{ @Override pulicvoidaddUser(Stringname){ System.out.println("添加用户:"+name); } } //处理器 pulicclassLogInvocationHandlerimplementsInvocationHandler{ privatefinalOjecttarget; pulicLogInvocationHandler(Ojecttarget){ this.target=target; } @Override pulicOjectinvoke(Ojectproxy,Methodmethod,Oject[]args)throwsThrowale{ System.out.println("开始执行:"+method.getName()); Ojectresult=method.invoke(target,args); System.out.println("执行结束"); retnresult; } } //使用示例 pulicclassJdkProxyDemo{ pulicstaticvoidmain(String[]args){ UserServtarget=newUserServImpl(); UserServproxy=(UserServ)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInteces(), newLogInvocationHandler(target) ); proxy.addUser("张三"); } }

JDK

CGLI

    通过继承目标类生成类使用MethodInterceptor接口实现逻辑SpringAOP默认使用此方式

//目标类(无需实现接口) pulicclassUserServ{ pulicvoidaddUser(Stringname){ System.out.println("添加用户:"+name); } } //CGLI处理器 pulicclassLogMethodInterceptorimplementsMethodInterceptor{ @Override pulicOjectintercept(Ojectoj,Methodmethod,Oject[]args,MethodProxyproxy) throwsThrowale{ System.out.println("开始执行:"+method.getName()); Ojectresult=proxy.invokeSuper(oj,args); System.out.println("执行结束"); retnresult; } } //使用示例 pulicclassCgliProxyDemo{ pulicstaticvoidmain(String[]args){ Enhancerenhancer=newEnhancer(); enhancer.setSuperclass(UserServ.class); enhancer.setCallack(newLogMethodInterceptor()); UserServproxy=(UserServ)enhancer.create(); proxy.addUser("张三"); } }

CGLI

Jassist

    提供了更简单的API来修改字节码可以在运行时动态创建新的类支持直接编辑方法体

//目标接口 pulicinteceUserServ{ voidaddUser(Stringname); } //目标类 pulicclassUserServImplimplementsUserServ{ @Override pulicvoidaddUser(Stringname){ System.out.println("添加用户:"+name); } } //Jassist示例 importorg.apache.iatis.jassist.ClassPool; importorg.apache.iatis.jassist.CtClass; importorg.apache.iatis.jassist.CtConstructor; importorg.apache.iatis.jassist.CtField; importorg.apache.iatis.jassist.CtMethod; importorg.apache.iatis.jassist.Modifier; importja.lang.reflect.Constructor; importja.lang.reflect.Method; /** *@authorCoderJia *@create2024/12/22下午04:13 *@Description **/ pulicclassJassistDemo{ pulicstaticvoidmain(String[]args)throwsException{ UserServtarget=newUserServImpl(); ClassPoolpool=ClassPool.getDefault(); //定义类名称 StringclassName=target.getClass().getName()+"JassistProxy"; //创建类 CtClassproxyClass=pool.makeClass(className); //添加接口 Class<?>[]inteces=target.getClass().getInteces(); for(Class<?>anIntece:inteces){ proxyClass.addIntece(pool.get(anIntece.getName())); } //添加字段 CtFieldtargetField=newCtField(pool.get(target.getClass().getName()), "target",proxyClass); targetField.setModifiers(Modifier.PRIVATE); proxyClass.addField(targetField); //添加构造函数 CtConstructorconstructor=newCtConstructor( newCtClass[]{pool.get(target.getClass().getName())},proxyClass); constructor.setody("{this.target=$1;}"); proxyClass.addConstructor(constructor); //获取接口的所有方法并创建方法 for(Methodmethod:inteces[0].getDeclaredMethods()){ CtClassretnType=pool.get(method.getRetnType().getName()); StringmethodName=method.getName(); //获取参数类型 Class<?>[]paramTypes=method.getParameterTypes(); CtClass[]parameters=newCtClass[paramTypes.length]; for(inti=0;i<paramTypes.length;i++){ parameters[i]=pool.get(paramTypes[i].getName()); } //创建方法 CtMethodctMethod=newCtMethod(retnType,methodName,parameters,proxyClass); //生成方法体 Stringuilderody=newStringuilder(); ody.append("{\n"); ody.append("System.out.println(\"方法开始执行:").append(methodName).append("\");\n"); ody.append("longstart=System.crentTimeMillis();\n"); //处理返回值 if(!retnType.equals(CtClass.voidType)){ ody.append("Ojectresult="); } //调用目标方法 ody.append("this.target.").append(methodName).append("("); for(inti=0;i<parameters.length;i++){ if(i>0)ody.append(","); ody.append("$").append(i+1); } ody.append(");\n"); ody.append("longend=System.crentTimeMillis();\n"); ody.append("System.out.println(\"方法执行时间:\"+(end-start)+\"ms\");\n"); //返回结果 if(!retnType.equals(CtClass.voidType)){ ody.append("retn($r)result;\n"); } ody.append("}"); ctMethod.setody(ody.toString()); proxyClass.addMethod(ctMethod); } //生成类 Class<?>clazz=proxyClass.toClass(); Constructor<?>cons=clazz.getConstructor(target.getClass()); UserServproxy=(UserServ)cons.newInstance(target); proxy.addUser("张三"); } }

Jassist

A

    直接作JVM字节码指令性能最优但使用复杂需要深入理解字节码结构

pulicclassADemo{ pulicstaticvoidmain(String[]args){ //创建ClassWriter ClassWritercw=newClassWriter(ClassWriter.COMPUTE_MAXS); //创建类 cw.visit(V1_8,ACC_PULIC,"com/example/UserServProxy", null,"ja/lang/Oject", newString[]{"com/example/UserServ"}); //添加字段 cw.visitField(ACC_PRIVATE,"target","Lcom/example/UserServ;", null,null); //创建构造函数 MethodVisitorconstructor=cw.visitMethod(ACC_PULIC,"<init>", "(Lcom/example/UserServ;)V",null,null); constructor.visitVarInsn(ALOAD,0); constructor.visitMethodInsn(INVOKESPECIAL,"ja/lang/Oject", "<init>","()V",false); constructor.visitVarInsn(ALOAD,0); constructor.visitVarInsn(ALOAD,1); constructor.visitFieldInsn(PUTFIELD,"com/example/UserServProxy", "target","Lcom/example/UserServ;"); constructor.visitInsn(RETN); constructor.visitMaxs(0,0); constructor.visitEnd(); //创建方法 MethodVisitormethod=cw.visitMethod(ACC_PULIC,"addUser", "(Lja/lang/String;)V",null,null); //...添加方法字节码 //生成类字节码 yte[]code=cw.toyteArray(); //加载字节码 } }

主要区别总结

1、使用难度:

    JDK<CGLI<Jassist<AA需要对字节码指令非常熟悉

2、性能较:

    A>Jassist>CGLI>JDKA直接作字节码,性能最好

3、应用场景:

    JDK:适合简单的接口场景CGLI:适合未实现接口的类,SpringAOP默认选择Jassist:适合动态生成类和修改类的场景A:适合对性能要求极高的底层框架开发

4、局限性:

    JDK:只能接口CGLI:不能final类和方法Jassist:修改字节码时,需要了解类结构A:使用复杂,代码可读性差

选择建议

    如果目标类有接口,优先使用JDK如果没有接口,使用CGLI如果需要动态修改类的结构,考虑Jassist如果是开发底层框架且对性能要求极高,可以考虑A

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2025/01/8303.html

分享给朋友:

相关文章

电脑c盘哪些文件可以删除?

电脑c盘哪些文件可以删除?

电脑上的文件夹都是英文,很多朋友都不敢乱删,下面这几个文件夹里的文件,你可以放心删除。一、可删除的文件1、Backup这是一个备份文件夹,很多装机软件经常会把需要备份的东西,放在这个文件夹中。而当我们需要的软件正常保存之后,这些东西也就没有...

学了两个月网络安全,一直未入门怎么办,知乎大佬们给些建议吧?

学了两个月网络安全,一直未入门怎么办,知乎大佬们给些建议吧?

你才学两个月,就想入门,笑不活了,我学了8年了,还被人说是个菜鸟。我学了这么多的渗透,依然挖不到自己的漏洞。ailx10:学习CSRF漏洞ailx10:学习PHP XXE漏洞ailx10:学习CORS漏洞ailx10:学习ClickJack...

支付宝碰一碰市场如何?

支付宝碰一碰市场如何?

今年,支付宝又整了新的大活,即无须扫码即能完成支付操作的“支付宝碰一碰”正式登场。下面就来给大家分析分析,这是个什么情况,为什么都在说能赚钱。支付宝碰一下怎么赚钱的?都有谁能赚到这份钱?1.支付宝碰一下原理支付宝碰一下的本质依旧是“条码支付...

马云也搞不明白:为什么现在用户偏爱微信支付,而不是支付宝?

这题我会,我教马云一招。你直接把你那破比支付宝的代码全删了,重新写一个。打开支付宝直接就是一个大大的支付码,然后右上角按一下就是扫一扫。你要是还想保留你的其他那些乱七八糟的功能,麻烦将他们全部做到下拉菜单里。你这么设计我不说你能干死微信,但...

为什么说不懂电脑的不要碰AMD?

作为一个资深垃圾佬,说缺点前,先说优点吧AMD CPU(后续简称AU)的优点:处理器对比Intel,三级缓存更大,最明显的感知就是,网游帧数更高(5900X,7900X之类高端型号都是双CCX共享大缓存,反而不如次一点的CPU帧数更高);相...

PHP承载百万/天 访问量需要用到什么技术?

当年做一个百万PV的商城,也不过是两台2c4g的阿里云虚机罢了(其实一台就够,另外一台主要的逼着大家一定开发的时候一定要有负载均衡和横向扩容的意识)。当时框架还是Thinkphp3.2,框架提高运行效率的开关全打开,标准的lnmp模式,单机...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。