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 这篇文章几乎是翻译了上面的文章,但翻译的不是很好
相关推荐
Java Instrumentation 和 Javaassist 是两种在 Java 应用程序中实现动态代码修改和增强的关键工具。RASP(Runtime Application Self-Protection)是一种安全技术,它允许应用程序在运行时检测和防御潜在的攻击。在这...
为了克服这些问题,可以直接用Java编写工具,结合反射和Javaassist技术,生成更灵活且定制化的payload。这种方式虽然更标准,但需要对Java语言和其内部机制有深入理解。 在二进制角度构造Payload的过程中,分析生成...
本文主要介绍了一个强大的Java字节码处理类库——Javaassist。 Javaassist是一个开源库,允许开发者在运行时动态地修改或者创建Java类。它提供了一种简洁的API,使得程序员无需深入了解字节码的细节就能实现复杂的...
Javaassist是一个开源库,主要用在Java应用程序中动态修改类和类库。它提供了一种简单的方法来操作字节码,使得开发者可以在运行时创建和修改类。在Java世界里,这种技术通常被称为字节码工程,对于实现如AOP(面向...
本文主要介绍了面向切面编程(AOP)和字节码插桩(Javaagent+Javaassist/Byte-Buddy)两种非侵入式方法增强方式的实现原理,并分析验证了这两种方法在实际项目中的应用效果。 面向切面编程(AOP)是一种编程技术,...
Java Agent 和 Javaassist 是在 Java 应用程序中实现非侵入式监控和埋点的关键技术。Java Agent 提供了一种在类加载到 JVM 之前进行拦截和修改的能力,而 Javaassist 是一个开源库,允许我们动态地修改字节码,使得...
1. **插桩技术**:Javaassist的核心功能之一就是插桩,它允许开发者在程序的特定位置插入额外的代码,而无需更改原始源代码。这种技术在调试、性能分析和日志记录等方面非常有用。通过Javaassist,开发者可以创建和...
本示例"JavaAgent-agentmain方式 demo"着重展示了如何使用JavaAgent的`agentmain`方法以及相关的Javaassist和VirtualMachine技术。 JavaAgent主要通过两个入口点与应用程序交互:`premain`和`agentmain`。`premain`...
Javaassist是一个开源库,主要用在Java编程中,它提供了在运行时修改字节码的能力。这个"javassist-3.7.GA.zip"压缩包是针对Java开发者的,特别是那些使用Struts2.2.1框架的开发者,因为它是构建该框架环境时可能...
Javaassist是一个开源库,主要用在Java编程中,它提供了对字节码操作的强大功能,使得程序员可以在运行时动态修改类或创建新的类。这个"javassist-3.9.0.GA.jar.zip"文件包含了Javaassist库的版本3.9.0 GA,这是一个...
Javaassist是一个开源的类库,它允许我们在运行时创建和修改Java类。通过解析类的字节码,我们可以插入新的方法、修改现有方法的实现,甚至改变类的结构。在JavaAgent的例子中,Javaassist是用于在程序运行时实现...
其他 URL 文件,如 "去脚本之家看看.url"、"领取天猫淘宝内部优惠券.url" 和 "服务器软件.url" 看起来与 Javaassist 或 JAR 文件本身的技术内容关系不大,可能是为了提供额外的信息资源,如教程链接、优惠信息或其他...
在"javassistDemo"项目中,开发者可能通过以上技术展示了如何使用Javaassist进行类的动态修改和创建,同时也可能演示了如何结合Charles进行网络调试。理解这些知识点对于深入学习Java的动态性、网络调试和AOP编程...
Javaassist是一个开源库,它允许在运行时对Java类进行操作和修改。这个"javassistDemo.zip"压缩包提供了一个示例,展示了如何利用Javaassist库动态修改Java类的方法。在Java应用程序中,这种能力非常有用,特别是在...
在Java世界中,JSR 330(Java标准版330)是一个重要的依赖注入(Dependency Injection,简称DI)规范,它定义了标准的注解来管理对象的生命周期和依赖关系。`AssistedInject`是Google提供的一个库,它是Guice框架的...
javaassist和asm各有优势,javaassist语法相对简洁,易于学习和使用,适合对字节码操作不太熟悉的开发者。而asm则提供了更为强大的功能,可以进行细粒度的字节码操作,适合需要高度定制字节码操作的场景。通常,当...
动态代理在Java编程中是一种非常重要的技术,它允许我们在运行时创建对象的代理,从而可以在不修改原有代码的情况下,为对象添加额外的功能。本压缩包包含关于三种主要的动态代理实现方式:JDK动态代理、CGLIB以及...
Javaassist是一个强大的字节码操作库,它允许程序员在运行时动态修改或创建Java类。这个库被广泛用于实现AOP(面向切面编程)、元编程以及动态代理等高级编程技术。在这里,我们讨论的是javassist的三个不同版本:...
Javaassist 是一个强大的 Java 字节码操作库,它允许开发者在运行时动态修改或创建类。这个库在软件开发中的主要用途是实现元编程,即在程序运行时修改程序的行为。`javassist-3.18.2-GA.jar` 是 Javaassist 的一个...
Javaassist是一个开源库,它允许我们在运行时动态地修改或创建Java类。这个强大的工具广泛应用于框架、代理生成以及AOP(面向切面编程)等领域。在本文中,我们将深入探讨如何结合Javaassist和注解(Annotation)来...