Javaassist是一个高层的Java字节码处理类库,能运行时动态生成类,修改类。Javaassit能动态生成类的基础源于Java Class的字节码技术:只要遵从规范,Java Class可以来自任何地方。
类似的技术还有:bcel,asm等,他们相对于Javaassit,偏向底层,效率较高,但编码难度更高(需要了解JVM指令)。
Javaassist是Jboss的一个子项目,其特点是简单:不需要了解底层JVM指令,直接用Java代码编写,容易理解,并且现在生成代码效率和以上两种技术相差已经很小。
Javaassist是一个日本人
Shigeru Chiba
开发的。
例子
动态生成一个全新的类// ClassPool包含所有动态生成的类,getDefault()返回默认的ClassPool, ClassPool cp = ClassPool.getDefault(); // 动态生成一个类 CtClass gclazz = cp.makeClass("org.jamee.demo.javaassist.GeneratedClass"); CtMethod gmethod = CtMethod .make("public void sayHello() { System.out.println(\"Hello Javaassist\"); }", gclazz); gclazz.addMethod(gmethod); // 转换成Class Class<?> gc = gclazz.toClass(); // 将该CtClass从ClassPool中移除, gclazz.detach(); // 调用方法 Object ginst = gc.newInstance(); Method gm = gc.getMethod("sayHello"); gm.invoke(ginst);
输出:
Hello Javaassist
动态修改类
测试目标类
class TestClass { public int compute(int param) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return param + 1000; } }
修改类
// ClassPool包含所有动态生成的类,getDefault()返回默认的ClassPool, ClassPool cp = ClassPool.getDefault(); // 该ClassPool默认从java lib,ext,classpath搜索class文件,并生成一个CtClass返回 CtClass clazz = cp.get("org.jamee.demo.javaassist.TestClass"); // 修改compute方法 CtMethod method = clazz.getDeclaredMethod("compute"); // $args,参数($1,第一个参数,$2,$3以此类推) ,$_:返回值 method.insertAfter("System.out.println(\"compute called with param: \" + java.util.Arrays.toString($args) + \", return: \" + $_);"); // 转换成Class,这一步也载入了修改后的Class。注意:必须保证之前这个Class没有载入过,不然会报异常:java.lang.LinkageError,因为JVM不允许一个class多次加载 clazz.toClass(); // 将该CtClass从ClassPool中移除, clazz.detach(); // 这时载入的TestClass已经被修改 TestClass test = new TestClass(); // 调用方法 test.compute(5);
输出:
compute called with param: [5], return: 1005
拦截方法
Javaassist的另外一个用法是拦截方法
ProxyFactory factory = new ProxyFactory(); // 设置父类,ProxyFactory将会动态生成一个类,继承该父类 factory.setSuperclass(TestClass.class); // 设置过滤器,判断哪些方法调用需要被拦截 factory.setFilter(new MethodFilter() { public boolean isHandled(Method m) { if (m.getName().equals("compute")) { return true; } return false; } }); Class<?> c = factory.createClass(); TestClass object = (TestClass) c.newInstance(); // 设置拦截处理 ((Proxy) object).setHandler(new MethodHandler() { public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { long start = System.currentTimeMillis(); try { return proceed.invoke(self, args); } catch (Exception e) { throw e; } finally { long taken = System.currentTimeMillis() - start; System.out.println("call method: " + thisMethod.getName() + " take: " + taken + "ms"); } } }); // 调用方法 System.out.println(object.compute(11));
输出:
call method: compute take: 3002ms
1011
从例子可以看出Javaassist可以修改类,创建类,创建方法,修改方法,拦截方法。实际上通过Javaassist你还可以:定义包,创建字段属性,访问注解(Annotation),定义接口等等。
限制
(1)不支持java5.0的新增语法(enum和泛型:由于泛型是运行时擦除的,因此可以直接去除类型变量),不支持注解修改
(7)不支持变长参数,需要改成数组
(8)插入的同一个方法代码前后的局部变量无法使用
例如:
void foo () {
//insert before
int a= 5;
....
// insert after
c = a // a is not defined
}
解决办法:
a. 创建一个field
b. 添加一个新方法:foo$impl,方法体拷贝旧的foo方法体,而新的foo,调用foo$impl
void foo () {
int a= 5;
foo$impl($$);
c = a
}
void foo$impl() {
...
}
参考
http://jboss-javassist.github.io/javassist/ 官网
http://jboss-javassist.github.io/javassist/tutorial/tutorial.html Jboss网站文档
http://zhxing.iteye.com/blog/1703305 这篇文章几乎是翻译了上面的文章,但翻译的不是很好
相关推荐
JavaAgent技术的Demo,agentmain方式 采用Javaassist技术实现字节码修改,VirtualMachine技术实现运行时代码织入
JavaAgent技术的Demo,agentmain方式 采用Javaassist技术实现字节码修改,VirtualMachine技术实现运行时代码织入
非常好用的 Microsoft Visual Studio 插件,自动识别各种关键字,系统函数,成员变量,自动给出输入提示,自动更正大小写错误,自动标示错误,等等。在Visual Studio .NET 2005 中, 支持 C/...很高兴能与大家交流技术!
可选的 System z Application Assist Processor(zAAP)提供了一种经济有效且专门化的 Java:trade_mark: 执行环境,从而提供了更高的性价比。用于灵活性部署 Linux:registered: 工作负载的专业引擎和内置 Parallel ...
可选的 System z Application Assist Processor(zAAP)提供了一种经济有效且专门化的 Java:trade_mark: 执行环境,从而提供了更高的性价比。用于灵活性部署 Linux:registered: 工作负载的专业引擎和内置 Parallel ...
Spring-generator 是基于 javafx8 开发的图形界面 Spring 代码生成器,使用 Apache FreeMarker 作为代码文件的模板,用户可以一键将数据库中的表生成为任意风格的 .java 代码文件(比如经典的三层模型)。 Spring-...
一款基于Eclipse SWT技术上的双向Java Gui设计软件。具备SWT设计以及Swing设计两个主要功能。该软件会被作为一个插件镶嵌入Eclipse以及其他一些兼容的IDEs中 note:WindowBuilder Pro is a market-leading GUI ...
一款基于Eclipse SWT技术上的双向Java Gui设计软件。具备SWT设计以及Swing设计两个主要功能。该软件会被作为一个插件镶嵌入Eclipse以及其他一些兼容的IDEs中 note:WindowBuilder Pro is a market-leading GUI ...
使用的技术包括... Java脚本 节点 ≫────≪•◦目标◦·≫────≪ + Assist companies & managers in creating a team profile page + Run a Team Profile generator from Terminal using node.js + ...
Java脚本≫────≪•◦目标◦·≫────≪ + Assist users in creating a 'notebook' of sorts+ Allow users to write and save notes as needed+ Provide an app which helps users organise thoughts & ...
1.2用户帮助和技术支持.....................................................................................................14 1.3 DB2服务器................................................................
1.2用户帮助和技术支持.....................................................................................................14 1.3 DB2服务器................................................................