1.读写字节码

Javassist是用来处理java字节码的类库。字节码保存在二进制文件中称为类文件。每个类文件夹包括一个java类或接口。

Javasssist.CtClass这个类是一个类文件的抽象表示。一个CtClass(compile-time class编译时类)对象处理一个类文件。下面是个简单的例子:

ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("test.Rectangle");cc.setSuperclass(pool.get("test.Point"));cc.writeFile();

这个程序首先包括了一个ClassPool对象,它javassist是用来修改字节码的。ClassPool对象是一个CtClass对象容器。它读取类文件根据需要构建CtClass对象,并且记录构建的对象以便响应最新的访问。修改类的定义,用户首先必须从ClassPool对象引用到一个CtClass对象表示。ClassPool中的get()方法就是这个作用。上面的例子展示,CtClass对象表示了ClassPool中的test.Rectangle对象。ClassPool的getDefault()搜索默认的系统搜索路径。

从实现的角度说,ClassPool是一个CtClass对象的hash表,类名做为keyClassPoolget()搜索hash表找到与指定key关联的CtClass对象。如果没有找到CtClass对象,get()读一个类文件构建新的CtClass对象,它是被记录在hash表中然后返回这个对象。

在ClassPool对象中的CtClass对象可以被编辑修改(如何修改在后面说明)。上面的例子中,把test.Rectangle的父类改为了test.Point。这个改变在执行writeFile()后实现。

writeFile()转换CtClass对象到一个类文件中并写到本地磁盘。Javassist还提供了一个方法直接得到修改的字节码。得到字节码,执行toBytecode():byte[] b = cc.toBytecode(); 也以直接载入CtClass:Class clazz = cc.toClass();toClass()请求当前线程的类载入器载入CtClass表示的类文件。它返回一个java.lang.Class对象来表示载入的类。

定义一个新类 定义新类,在ClassPool中执makeClass().

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.makeClass("Point"); 

这个例子定义了没有成员的Point类。CtNewMethod的工厂方法可以构建Point的成员方法,用CtClass的addMethod()加入到Point中。    makeClass()不能建接口,ClassPool的makeInterface()可以。CtNewMethod的abstractMethod()可以为接口构建方法。 

2.冻结的类

如果CtClass通过writeFile(),toClass(),toBytecode()转换了类文件,javassist冻结了CtClass对象。以后是不允许修改这个 CtClass对象。这是为了警告开发人员当他们试图修改一个类文件时,已经被JVM载入的类不允许被重新载入。

一个冻结的CtClass可以被解冻,因为修改类定义可以被允许。例如:

CtClasss cc = ...;
   :
cc.writeFile();//冻结
cc.defrost();//解冻
cc.setSuperclass(...);   // OK since the class is not frozen.可以重新操作CtClass,因为被解冻了

Defrost()执行后,CtClass对象将可以再次修改。

如果ClassPool.doPruning被设置为true,javassist将修剪被冻结的CtClass对象的数据结构,以减少内存消耗。修剪会丢掉对象中不需要的属性(attribute_info structures)。例如,Code_attribute结构(method bodies)。因此,CtClass对象修剪后,方法的字节码除了方法名,方法签名和注释,其它将不可访问。修剪的CtClass对象并不能再解冻。ClassPool.doPruning默认的值为false。

不允许修剪执行了CtClass.stopPruning()的对象:

CtClasss cc = ...;
cc.stopPruning(true);//不允许修剪CtClass
cc.writeFile();         // convert to a class file.
// cc is not pruned.
注:如果提示例如com.samples.Programmer class is frozen,则肯定执行了writeFile(),toClass(),toBytecode()等操作,只要通过defrost()方法解冻即可,如果出现例如com.samples.Programmer was pruned.,则该CtClass被修剪了,只要通过
stopPruning(true)方法即可阻止修剪

注意:调试的时候,你可能想暂时的停止修剪和冻结并写一个类文件到磁盘,debugWriteFile()是为这个目的做的方法。它停止修剪,写一个类文件,解冻它,然后再次修剪(如果是初始化)。

3.类搜索路径

默认的ClassPool通过static方法ClassPool.getDefault()返回与JVM一样的搜索路径。如果程序运行在一个web服务器,如JBoss,Tomcat,ClassPool对象可以找不到用户的类,因为web 服务器用多个类载入器(class loader)作为载入器。这种情况,附加的类路径必须注册到ClassPool。应该为pool 提供一个ClassPool 对象:

pool.insertClassPath(new ClassClassPath(this.getClass()));

这段程序注册了用来载入类对象的类路径。可以用任何类对象作为参数替换this.getClass()。注册的路径用来载入类 。

可以注册一个目录名作为类搜索路径。例如,下面的例子加入了一个目录/usr/local/javalib作为搜索路径:

ClassPool pool = ClassPool.getDefault();

pool.insertClassPath("/usr/local/javalib");

这个搜索路径不仅可以是目录,还可以是URL:

ClassPool pool = ClassPool.getDefault();

ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");

pool.insertClassPath(cp);

这个程序加入”http://www.javassist.org:80/java/” 到类搜索路径。这个URL只是搜索属于org.javassist包的类。例如,载入org.javassist.test.Main,它的类文件将被得到:

http://www.javassist.org:80/java/org/javassist/test/Main.class

另外,可以直接把一个byte数组给一个ClassPool对象,构建一个CtClass对象从这个数组。ByteArrayClassPath,例如:

ClassPool cp = ClassPool.getDefault();

byte[] b = a byte array;

String name = class name;

cp.insertClassPath(new ByteArrayClassPath(name, b));

CtClass cc = cp.get(name);

得到的CtClass对象表示通过b指定的一个类,ClassPool从ByteArrayClassPath读一个类文件,如果执行get(),需要用类名。

如果不知道类的全名,可以用ClassPool中的makeClass():ClassPool cp = ClassPool.getDefault();

InputStream ins = an input stream for reading a class file;

CtClass cc = cp.makeClass(ins);

makeClass()从输入流中返回CtClass对象。可以用makeClass()把想要修改的类放入ClassPool。如果搜索路径包括一个大的jar文件,它可以提高性能。当ClassPool需要读取一个类文件,它可以为每个类文件重复搜索整个jar文件夹。makeClass()可以有效的搜索。makeClass()构建的CtClass,保存在ClassPool,并且类文件不再被读。

用户可以扩展类搜索路径。可以定义一个实现ClassPath接口的新类,ClassPool的insertClassPath()给了一个类的实例。它允许一个非标准资源包含在搜索路径中。

Javassist 字节码操作的更多相关文章

  1. JAVAssist字节码操作

    Java动态性的两种常见实现方式 字节码操作 反射 运行时操作字节码可以让我们实现如下功能: 动态生成新的类 动态改变某个类的结构(添加/删除/修改  新的属性/方法) 优势: 比反射开销小,性能高 ...

  2. 字节码操作JAVAssist

    字节码操作Javassist 字节码:字节码是设计被用来将代码高效的传送给多种软件平台.硬件平台,字节码的设计也实现了Java的平台无关性,字节码比机器码更抽象,它通常被认为是包含了一个可执行文件的二 ...

  3. Javassist 字节码 简介 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. Javassist 字节码 语法 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. 尚学堂 216 java中的字节码操作

    所谓的字节码操作就是操作我们已经加载的字节码 接下来我们重点来讲解javaassist类库 使用需要下载jar包,把jar包添加到对应的工程之后 package com.bjsxt.test; pub ...

  6. Java动态性 字节码操作

    Java动态性的两种常见方式:-字节码操作 - 反射;字节码操作比反射开销小,性能高,JAVAasist性能高于反射,低于ASM 运行时操作字节码可是实现  : 动态生成新的类:动态的改变某个类的结构 ...

  7. [19/04/20-星期六] Java的动态性_字节码操作(Javassist类库(jar包),assist:帮助、援助)

    一.概念 [基本] /** * */ package cn.sxt.jvm; import javassist.ClassPool; import javassist.CtClass; import ...

  8. 8.5(java学习笔记)8.5 字节码操作(javassist)

    一.javassist javassist让我们操作字节码更加简单,它是一个类库,允许我们修改字节码.它允许java程序动态的创建.修改类. javassist提供了两个层次的API,基于源码级别的和 ...

  9. 字节码操作、javassist使用

    一.功能 1.动态生成新的类 2.动态改变某个类的结构(添加.删除.修改   新的属性.方法) 二.优势 1.比反射开销小,性能高 2.JAVAasist性能高于反射,低于ASM 使用javassis ...

随机推荐

  1. 分析移动端APP的网络请求抓包

    为了方便,本文以 iOS 系统来进行演示. 使用代理 移动操作系统中都有可以设定系统代理的设置,比如在 iOS 中可以通过 Settings->WLAN 看到很多 Networks,通过点击它们 ...

  2. JQ001-认识jQuery 和 JQ002-jQuery选择器

    JQ001-认识jQuery jQuery环境配置:将jQuery.js文件引入到html页面中即可. 代码如下: <!DOCTYPE html> <html> <hea ...

  3. css之图片路径

    关于背景图片url路径:图片和调用文件在两个不同根下的(不在同一个包(文件夹)中),要用相对路径,举例"../images/cq.gif":图片和调用文件是在一个根下的直接孩子,用 ...

  4. tyvj1114 搭建双塔

    描述     2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔.    Mr. F有 ...

  5. 超酷jQuery进度条加载动画集合

    在丰富多彩的网页世界中,进度条加载动画的形式非常多样,有利用gif图片实现的loading动画,也有利用jQuery和CSS3实现的进度加载动画,本文主要向大家介绍很多jQuery和CSS3实现的进度 ...

  6. 【bzoj1426】收集邮票

    题目描述 有n种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由于凡凡也很喜欢邮票,所 ...

  7. Spring中集合类型属性注入

    我们都知道如何去注入普通属性的值,非常简单,那么我们如何去注入开发中常见的集合类型的属性了,别急,往下看. 这里将介绍如何给Map list set Array Properties 这些属性注入值. ...

  8. SpringMVC上传文件的三种方式

    直接上代码吧,大伙一看便知 这时:commonsmultipartresolver 的源码,可以研究一下 http://www.verysource.com/code/2337329_1/common ...

  9. VBA之文件筛选

    在工作中,经常会碰到从一堆腐朽的source中按照一个列表去筛选出来现在还要用的source文件. 这个如果用vba来实现的话,会节省大量的时间,而且不会出错. 前提说明: 将想要复制的文件名列表放在 ...

  10. ecshop调用后台指定广告位下所有广告循环

    ecshop本身的广告调用规则是:对某个广告位下的广告列表随机显示其中一条. 而我们有时需要将某个广告位下的所有广告全部显示出来,那么如何处理呢,下面就自己做了一个函数: \includes\lib_ ...