当前位置:首页 > 每日看点

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

卡卷网2年前 (2025-01-10)每日看点255

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

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

分享给朋友:

相关文章

手机买16+256的还是12+512的好?

手机买16+256的还是12+512的好?

到底选大内存还是大存储,一直以来是很多朋友的纠结点,大内存意味着可以应用多开不卡顿,大存储则是可以存入更多文件、应用,如果两个配置价格差距不大(如0-200元),确实有点难选。 不过从实际体验出发,大存储的手机显然更应该优先选择才是。首先,…

网易云音乐里有哪些打动你的评论?

1. “如果我被强奸了,有人说我会失去贞操。” “我怎么失去贞操了呢?” “我的贞操不在我的阴道里。” “失去贞操的是强奸犯,而不是被强奸的人。” 2. 但要记得那年海边的烟火,我们不拘一格 ,嘲笑过生活。 ………网易云热评《这样就很好》…

大量刷短视频,会让大脑变笨拙吗?

会。 我曾经是一名高三学生,亲身实践过。 当时集中突破语文,每天都在刷语文卷。然后有一天想躺一下刷手机,结果短视频刷完了,我再去看哪些文章,只觉头晕眼花,难以理解文字。不过好在这种情况是短时间的,过了一天我的能力又恢复了。 在我看来,长期刷…

如何看待台积电,三星相继停供大陆7nm及更先进芯片?

在这个事出来之前,我就看到过一个说法,两家Foundry可以在中东建厂,让中东的Fab去干“脏活”。本质上是国内企业搞几个中东的代理人,装作是中东的初创Fabless企业去下单,人家Foundry大概率睁一只眼闭一只眼,只管数钱。然而,紧接…

国外有没有像国内闲鱼这样的二手平台?

国外有没有像国内闲鱼这样的二手平台?

在当今全球市场,二手电商正迅速崛起,成为全球消费者购物的热门选择。很多国外的消费者,特别是那些 注重可持续和环保 的人群,包括富裕的消费者都经常购买二手商品。对电商卖家来说,进军二手平台是个很好的创收机会。尤其是在美国, 美国二手物品交易平…

发表评论

访客

看不清,换一张

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