java 动态字节码技术和类加载
字节码有什么用?
1、对类的基本信息进行操作 ,可以新增、删除、修改类、属性和方法;
2、应用场景:Lombok 插件、AOP、动态修改class文件、网页上的在线执行java代码也是字节码实现的;
2、Lombok 插件就是用字节码实现,只用Data注解就可以给属性自动加上get和set方法
4、
常见的字节码操作类库:
BCEL: 深入汇编底层语言进行类库操作;
ASM: 轻量级字节码操作框架,直接涉及到jVM底层的操作和指令;高性能、高质量
CGLB: 生成类库,基于ASM实现
javassist :开源框架,编辑和创建Java字节码的类库,我们这里主要介绍javassist
javassist 框架
优势:比反射开销小、性能高;但是比ASM低;跟cglib差不多,使用简单。很多开源框架都在使用它。可进行修改已有方法的方法体(插入代码到已有方法体)、新增方法 、 删除方法;
缺点:不支持数组初始化、不支持内部类和匿名类、不支持continue和break表达式、不支持泛型和枚举、某些继承关系也不支持;
类加载器
我们的代码运行的时候,首先会将后缀为java的文件编译成后缀为 class 的文件,class文件中保存着java代码转换后的虚拟机指令,当需要使用到某个类时,虚拟机会加载它的 class 文件,并创建class对象,将class加载到虚拟机内存,这个过程称为类加载,类加载过程图如下:
我们使用一个对象的时候,在虚拟机底层已经帮我们加载好了class对象,所以我们直接用就好了;
类加载器常用方法( ClassLoader)
loadClass(String)
当类加载请求到来时,先从缓存中查找该类对象,如果存在直接返回,如果不存在则交给该类加载去的父加载器去加载,倘若没有父加载则交给顶级启动类加载器去加载,最后倘若仍没有找到,则使用findClass()方法去加载;
findClass(String)
根据名称或者位置加载Class字节码,然后使用defineClass 通常由子类去实现,如果需要自定义ClassLoader的话,必须重写该方法。
defineClass(byte[] b, int off, int len)
defineClass()方法是用来将byte字节流解析成JVM能够识别的Class对象(ClassLoader中已实现该方法逻辑),通过这个方法不仅能够通过class文件实例化class对象,也可以通过其他方式实例化class对象,如通过网络接收一个类的字节码,然后转换为byte字节流创建对应的Class对象,defineClass()方法通常与findClass()方法一起使用,一般情况下,在自定义类加载器时,会直接覆盖ClassLoader的findClass()方法并编写加载规则,取得要加载类的字节码后转换成流,然后调用defineClass()方法生成类的Class对象,简单地说就是把class字节码文件转化为Class对象
resolveClass(Class≺?≻ c)
使用该方法可以使用类的Class对象创建完成也同时被解析。前面我们说链接阶段主要是对字节码进行验证,为类变量分配内存并设置初始值同时将字节码文件中的符号引用转换为直接引用。
- 点赞
- 收藏
- 关注作者
评论(0)