卡卷网
当前位置:卡卷网 / 每日看点 / 正文

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

作者:卡卷网发布时间:2025-01-11 16:39浏览数量:70次评论数量:0次

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

JDK

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

//目标接口pulicinteceUserServ{voidaddUser(Stringname);}//目标类pulicclassUserServImplimplementsUserServ{@OverridepulicvoidaddUser(Stringname){System.out.println("添加用户:"+name);}}//处理器pulicclassLogInvocationHandlerimplementsInvocationHandler{privatefinalOjecttarget;pulicLogInvocationHandler(Ojecttarget){this.target=target;}@OverridepulicOjectinvoke(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{@OverridepulicOjectintercept(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{@OverridepulicvoidaddUser(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){//创建ClassWriterClassWritercw=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

END

免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。

卡卷网

卡卷网 主页 联系他吧

请记住:卡卷网 Www.Kajuan.Net

欢迎 发表评论:

请填写验证码