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

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

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

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

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

分享给朋友:

相关文章

小米14 Pro和Redmi K70Pro怎么选?

小米14 Pro和Redmi K70Pro怎么选?

两款手机都使用了最新的骁龙8Gen3旗舰芯片,性能都是顶级,但是两款手机定位不同,卖点不同,红米K70 Pro定位主打性能的旗舰入门手机,小米14Pro定位旗舰中高端手机。具体根据个人需求与预算来选择:两款手机的相同、相似点:都使用了骁龙8...

k70和红米note14pro+咋选啊?

k70和红米note14pro+咋选啊?

首选红米K70,可满足题主的功能需求。红米 Note 14 pro+的使用者定位并不是学生,红米K70的使用者定位才是学生。一、k70和红米note14pro+各自的参数红米K70推出的定位初衷,是主打性能为主。最佳使用对象是喜欢游戏者,...

小米14和华为mate60怎么选?

手持荣耀20,用了五年多了,使用仍然较为流畅,但是电池不太行了,于是2024年8月在家乡的小米之家购买了小米14(12+256),用了快两个月吧,说说使用体验。 外观层面,由于我使用的荣耀20放在现在妥妥地属于小屏,习惯了小屏...

下一个风口最可能是什么?

下一个风口最可能是什么?

肯定是一带一路了,国内没什么卷的空间了,现在国家正在给一带一路的第三世界国家建设基础设施,等交通打通之后,就是通信打通,通信打通就是贸易打通,未来我建议大家重仓小语种,阿拉伯语最值得学(也有其他小语种自己去查一带一路国家),将来去其他国家随...

荣耀magic 7 首发的应该都收到货了,感觉怎么样?

8号入手magic7,跟mate40pro比。优点:1、电池真耐用,充电块,华为电池也是新换的但是明显荣耀耐用;2、系统明显快多了,mate40pro下半年开始卡的不行,实在受不了了。3、声音、震动效果提升明显,指纹反应灵敏很多。 缺点:1...

大家都是怎么把自己的粉丝增加到1000的呢?

大家都是怎么把自己的粉丝增加到1000的呢?

截至2024年10月30日,关注者总数1137人,用时80天,增速约14人/天。2024年10月30日数据2024年8月10日开始创作,连续一周,1个关注者都没有。创作第7天,得到第一个关注,7天时间,写了8篇回答。当天得到关注,激动的心情...

发表评论

访客

看不清,换一张

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