`
jamie.wang
  • 浏览: 348569 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Javaassist技术

    博客分类:
  • Java
阅读更多

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和泛型:由于泛型是运行时擦除的,因此可以直接去除类型变量),不支持注解修改

(2)不支持数组的初始化,如String[]{"1","2"},除非只有数组的维度为1
(3)不支持内部类和匿名类
(4)不支持continue和break 表达式。
(5)方法重载支持不好。例如
class A {} 
class B extends A {} 
class C extends B {} 
 
class X { 
    void foo(A a) { .. }  
    void foo(B b) { .. }  
}
如果调用  x.foo(new C()),可能会调用foo(A) 。
 
(6)推荐开发者用#分隔一个class name和static method或者 static field。例如:
javassist.CtClass.intType.getName()推荐用javassist.CtClass#intType.getName()

(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 这篇文章几乎是翻译了上面的文章,但翻译的不是很好

http://javatar.iteye.com/blog/814426 性能的分析

分享到:
评论

相关推荐

    基于 Java Instrumentation + Javaassist 的简单 RASP.zip

    Java Instrumentation 和 Javaassist 是两种在 Java 应用程序中实现动态代码修改和增强的关键工具。RASP(Runtime Application Self-Protection)是一种安全技术,它允许应用程序在运行时检测和防御潜在的攻击。在这...

    【技术分享】二进制角度构造Java反序列化Payload .pdf

    为了克服这些问题,可以直接用Java编写工具,结合反射和Javaassist技术,生成更灵活且定制化的payload。这种方式虽然更标准,但需要对Java语言和其内部机制有深入理解。 在二进制角度构造Payload的过程中,分析生成...

    一个牛逼的 Java 字节码类库!(csdn)————程序.pdf

    本文主要介绍了一个强大的Java字节码处理类库——Javaassist。 Javaassist是一个开源库,允许开发者在运行时动态地修改或者创建Java类。它提供了一种简洁的API,使得程序员无需深入了解字节码的细节就能实现复杂的...

    javassist-3.18.1-GA.jar

    Javaassist是一个开源库,主要用在Java应用程序中动态修改类和类库。它提供了一种简单的方法来操作字节码,使得开发者可以在运行时创建和修改类。在Java世界里,这种技术通常被称为字节码工程,对于实现如AOP(面向...

    Java方法增强技术研究.pdf

    本文主要介绍了面向切面编程(AOP)和字节码插桩(Javaagent+Javaassist/Byte-Buddy)两种非侵入式方法增强方式的实现原理,并分析验证了这两种方法在实际项目中的应用效果。 面向切面编程(AOP)是一种编程技术,...

    第二课:调用链核心技术-Agent采集埋点实现1

    Java Agent 和 Javaassist 是在 Java 应用程序中实现非侵入式监控和埋点的关键技术。Java Agent 提供了一种在类加载到 JVM 之前进行拦截和修改的能力,而 Javaassist 是一个开源库,允许我们动态地修改字节码,使得...

    javassist 3.23.1版本

    1. **插桩技术**:Javaassist的核心功能之一就是插桩,它允许开发者在程序的特定位置插入额外的代码,而无需更改原始源代码。这种技术在调试、性能分析和日志记录等方面非常有用。通过Javaassist,开发者可以创建和...

    JavaAgent例子-agentmain方式 demo

    本示例"JavaAgent-agentmain方式 demo"着重展示了如何使用JavaAgent的`agentmain`方法以及相关的Javaassist和VirtualMachine技术。 JavaAgent主要通过两个入口点与应用程序交互:`premain`和`agentmain`。`premain`...

    javassist-3.7.GA.zip

    Javaassist是一个开源库,主要用在Java编程中,它提供了在运行时修改字节码的能力。这个"javassist-3.7.GA.zip"压缩包是针对Java开发者的,特别是那些使用Struts2.2.1框架的开发者,因为它是构建该框架环境时可能...

    javassist-3.9.0.GA.jar.zip

    Javaassist是一个开源库,主要用在Java编程中,它提供了对字节码操作的强大功能,使得程序员可以在运行时动态修改类或创建新的类。这个"javassist-3.9.0.GA.jar.zip"文件包含了Javaassist库的版本3.9.0 GA,这是一个...

    JavaAgent例子-agentmain方式

    Javaassist是一个开源的类库,它允许我们在运行时创建和修改Java类。通过解析类的字节码,我们可以插入新的方法、修改现有方法的实现,甚至改变类的结构。在JavaAgent的例子中,Javaassist是用于在程序运行时实现...

    javassist3150gajar_jb51

    其他 URL 文件,如 "去脚本之家看看.url"、"领取天猫淘宝内部优惠券.url" 和 "服务器软件.url" 看起来与 Javaassist 或 JAR 文件本身的技术内容关系不大,可能是为了提供额外的信息资源,如教程链接、优惠信息或其他...

    javassistDemo

    在"javassistDemo"项目中,开发者可能通过以上技术展示了如何使用Javaassist进行类的动态修改和创建,同时也可能演示了如何结合Charles进行网络调试。理解这些知识点对于深入学习Java的动态性、网络调试和AOP编程...

    javassistDemo.zip

    Javaassist是一个开源库,它允许在运行时对Java类进行操作和修改。这个"javassistDemo.zip"压缩包提供了一个示例,展示了如何利用Javaassist库动态修改Java类的方法。在Java应用程序中,这种能力非常有用,特别是在...

    AssistedInject,辅助注射jsr 330。.zip

    在Java世界中,JSR 330(Java标准版330)是一个重要的依赖注入(Dependency Injection,简称DI)规范,它定义了标准的注解来管理对象的生命周期和依赖关系。`AssistedInject`是Google提供的一个库,它是Guice框架的...

    byte code 操作

    javaassist和asm各有优势,javaassist语法相对简洁,易于学习和使用,适合对字节码操作不太熟悉的开发者。而asm则提供了更为强大的功能,可以进行细粒度的字节码操作,适合需要高度定制字节码操作的场景。通常,当...

    动态代理-jdk、cglib、javassist.zip

    动态代理在Java编程中是一种非常重要的技术,它允许我们在运行时创建对象的代理,从而可以在不修改原有代码的情况下,为对象添加额外的功能。本压缩包包含关于三种主要的动态代理实现方式:JDK动态代理、CGLIB以及...

    javassist18,20,22三个版本.zip

    Javaassist是一个强大的字节码操作库,它允许程序员在运行时动态修改或创建Java类。这个库被广泛用于实现AOP(面向切面编程)、元编程以及动态代理等高级编程技术。在这里,我们讨论的是javassist的三个不同版本:...

    javassist-3.18.2-GA.jar

    Javaassist 是一个强大的 Java 字节码操作库,它允许开发者在运行时动态修改或创建类。这个库在软件开发中的主要用途是实现元编程,即在程序运行时修改程序的行为。`javassist-3.18.2-GA.jar` 是 Javaassist 的一个...

    运用javassist和annotation修改class的特定method的class byte code

    Javaassist是一个开源库,它允许我们在运行时动态地修改或创建Java类。这个强大的工具广泛应用于框架、代理生成以及AOP(面向切面编程)等领域。在本文中,我们将深入探讨如何结合Javaassist和注解(Annotation)来...

Global site tag (gtag.js) - Google Analytics