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

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

卡卷网1年前 (2025-01-10)每日看点246

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

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

分享给朋友:

相关文章

创业:集思广益并完善您的商业理念

用史蒂夫乔布斯的话来说,“做伟大工作的唯一方法就是热爱你所做的事情。开始自己的事业是迈向自己喜欢的工作的一步。但是,从形成想法到创建商业网站,在您深入研究之前,需要考虑几个基本步骤和问题:您要解决什么问题?您的目标受众是谁?您的产品或服务与…

短剧推广怎么做,24年还能赚钱吗?

短剧推广怎么做,24年还能赚钱吗?

首先声明:短剧授权是免费的! 短剧授权是免费的! 短剧授权是免费的! 其次我们再聊聊,短剧推广到底赚不赚钱? 多的就不说了, 随便上个图片,给大家过过瘾! 然后,我们进入主题: 0粉丝账号,新手,应该如何申请短剧推广! 一、短剧推广变现…

夸克浏览器受欢迎的原因是什么?

夸克浏览器受欢迎的原因是什么?

这是可以说的嘛~ 哈哈,它比较吸引我的几点是:安全无广、页面简洁、功能丰富、反应速度快...... 首页页面支持自定义,喜欢什么样子都可以自己调整,没有花里胡哨的各种资讯推送,热搜日报整理归纳好,想看再点开查看,看着舒适度直接拉满! 实…

在 Kubernetes 中,Service 的实现原理是什么,它是如何实现服务发现的?

行,问的这个问题挺有意思,Kubernetes 里 Service 是怎么实现的,服务发现是怎么回事,咱就直说了。这事儿看起来挺玄乎,但掰开揉碎了讲,也就那么回事。你得把这事儿想得简单点,别一上来就被啥术语吓住了——其实全是些搬砖的套路。…

抖音有3,4万粉丝能挣多少钱?

抖音有3,4万粉丝能挣多少钱?

如果在抖音有100万粉丝,一个月能赚多少钱你知道吗?直接说答案: 抖音有100万粉丝,可能1分钱也赚不到...那视频有100万点赞,能赚多少钱?可能也是1分钱都赚不到... 新手需要通过抖音变现 [文章: 做为新手玩抖音要注意什么?怎样才能…

测试用例是怎么写的?

测试用例是怎么写的?

测试用例对于测试人员而言,虽说是最最基础的技能,但却非常重要。测试用例是支撑我们在测试道路上进一步学习其他测试技能的基本功。 那测试用例如何撰写,完整来说应该包含两部分内容: 内容1: 测试用例撰写(按照八大要素); 内容2: 测试用例(测…

发表评论

访客

看不清,换一张

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