cglib和jdk动态代理区别_java动态代理

动态代理作为java各框架的基础随处可见,比如spring、mybatis、rpc等都广泛涉及动态代理的应用,spring的aop基于jdk和CGlib两种方式实现动态代理,jdk只能实现基于接口的代理,CGlib通过继承能够实现非final类的代理,javassist通过源码层次来实现代理。

上述结论网上到处可见,我们只讲几个关键点:

1、动态代理是怎么创建的

动态代理的结果是要生成具体的动态代理类,代理类是程序在运行期动态生成的类,这个类和我们平时写代码.java文件里面的类是有区别的,.java文件里面的类需要经过编译成class文件然后jvm类加载器装入内存;运行期生成类肯定没有编译过程了,这时是直接根据class的数据结构生成对应的字节码由jvm类加载器装入的,无论通过jdk也好、还是CGlib、javassist,都是基于class数据结构直接生成字节码,大的结构如下图

a754ebfd05b3eaf18f22dc7ff759533c.png

2、class数据结构

既然动态代理最终都是通过class数据结构生成字节码的,那么class数据结构长啥样,如下图

7f4f40671e8e78e20b434202298a3a4e.png

3、jdk通过操作字节码生成代理的过程

通过jdk生成动态代理的过程在ProxyGenerator.java里面的private byte[] generateClassFile()方法,和上面class文件的结构保持一致

/*             * Write all the items of the "ClassFile" structure.             * See JVMS section 4.1.             */                                        // u4 magic;            dout.writeInt(0xCAFEBABE);                                        // u2 minor_version;            dout.writeShort(CLASSFILE_MINOR_VERSION);                                        // u2 major_version;            dout.writeShort(CLASSFILE_MAJOR_VERSION);            cp.write(dout);             // (write constant pool)                                        // u2 access_flags;            dout.writeShort(accessFlags);                                        // u2 this_class;            dout.writeShort(cp.getClass(dotToSlash(className)));                                        // u2 super_class;            dout.writeShort(cp.getClass(superclassName));                                        // u2 interfaces_count;            dout.writeShort(interfaces.length);                                        // u2 interfaces[interfaces_count];            for (Class> intf : interfaces) {                dout.writeShort(cp.getClass(                    dotToSlash(intf.getName())));            }                                        // u2 fields_count;            dout.writeShort(fields.size());                                        // field_info fields[fields_count];            for (FieldInfo f : fields) {                f.write(dout);            }                                        // u2 methods_count;            dout.writeShort(methods.size());                                        // method_info methods[methods_count];            for (MethodInfo m : methods) {                m.write(dout);            }                                         // u2 attributes_count;            dout.writeShort(0); // (no ClassFile attributes for proxy classes)

注意:为什么jdk只能代理接口,因为上面dout.writeShort(cp.getClass(superclassName));已经制定了父类Proxy,java只能继承一个类;

4、CGlib通过操作字节码生成代理的过程

CGlib是通过ASM操作字节码的,读写的类分别是ClassReader.java和ClassWriter.java

5、javassist通过操作字节码生成代理的过程

javassist后续补充

参考文档:https://tech.meituan.com/2019/09/05/java-bytecode-enhancement.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值