`
jamie.wang
  • 浏览: 339182 次
  • 性别: 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 性能的分析

分享到:
评论

相关推荐

    JavaAgent例子-agentmain方式

    JavaAgent技术的Demo,agentmain方式 采用Javaassist技术实现字节码修改,VirtualMachine技术实现运行时代码织入

    JavaAgent例子-agentmain方式 demo

    JavaAgent技术的Demo,agentmain方式 采用Javaassist技术实现字节码修改,VirtualMachine技术实现运行时代码织入

    Assist X插件

    非常好用的 Microsoft Visual Studio 插件,自动识别各种关键字,系统函数,成员变量,自动给出输入提示,自动更正大小写错误,自动标示错误,等等。在Visual Studio .NET 2005 中, 支持 C/...很高兴能与大家交流技术!

    IBM eServer zSeries 890产品手册

    可选的 System z Application Assist Processor(zAAP)提供了一种经济有效且专门化的 Java:trade_mark: 执行环境,从而提供了更高的性价比。用于灵活性部署 Linux:registered: 工作负载的专业引擎和内置 Parallel ...

    IBM eServer zSeries 890问题解答手册

    可选的 System z Application Assist Processor(zAAP)提供了一种经济有效且专门化的 Java:trade_mark: 执行环境,从而提供了更高的性价比。用于灵活性部署 Linux:registered: 工作负载的专业引擎和内置 Parallel ...

    Spring-generator一键生成数据库文件

    Spring-generator 是基于 javafx8 开发的图形界面 Spring 代码生成器,使用 Apache FreeMarker 作为代码文件的模板,用户可以一键将数据库中的表生成为任意风格的 .java 代码文件(比如经典的三层模型)。 Spring-...

    windows builder pro for eclipse 3.7 天涯浪子

    一款基于Eclipse SWT技术上的双向Java Gui设计软件。具备SWT设计以及Swing设计两个主要功能。该软件会被作为一个插件镶嵌入Eclipse以及其他一些兼容的IDEs中 note:WindowBuilder Pro is a market-leading GUI ...

    windows builder pro for eclipse 3.6 天涯浪子

    一款基于Eclipse SWT技术上的双向Java Gui设计软件。具备SWT设计以及Swing设计两个主要功能。该软件会被作为一个插件镶嵌入Eclipse以及其他一些兼容的IDEs中 note:WindowBuilder Pro is a market-leading GUI ...

    Team-Generator:编码训练营-第十周家庭作业

    使用的技术包括... Java脚本 节点 ≫────≪•◦目标◦·≫────≪ + Assist companies & managers in creating a team profile page + Run a Team Profile generator from Terminal using node.js + ...

    Notebooker:编码训练营-第11周的作业

    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 & ...

    db2数据库入门教程(官方中文版)

    1.2用户帮助和技术支持.....................................................................................................14 1.3 DB2服务器................................................................

    db2数据库入门官方教程(中文版)

    1.2用户帮助和技术支持.....................................................................................................14 1.3 DB2服务器................................................................

Global site tag (gtag.js) - Google Analytics