• Javassist介绍


    要想将编译时不存在的类在运行时动态创建并加载,通常有两种策略:
    1. 动态编译
    2. 动态生成二进制字节码(.class)
    对于第二种策略,实际上已经有诸多比较成熟的开源项目提供支持,如CGLib、ASM、Javassist等。这些开源项目通常都具备两方面的功能:
    1. 动态创建新类或新接口的二进制字节码
    2. 动态扩展现有类或接口的二进制字节码
    其中,CGLib的底层基于ASM实现,是一个高效高性能的生成库;而ASM是一个轻量级的类库,但需要涉及到JVM的操作和指令;相比而言,Javassist要简单的多,完全是基于Java的API,但其性能相比前二者要差一些。
    尽管如此,在性能要求相对低的场合,Javassist仍然十分有用,如JBoss中就调用了Javassist。
    Javassist的官方网站如下:
    http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
    如下的链接是一个很好的Javassist代码示例:
    http://yonglin4605.iteye.com/blog/1396494
    如下的链接深入研究了Javassist中的一些语法,其中第8小节处对参数形式的总结很有作用:
    http://zhxing.iteye.com/blog/1703305
    如下的链接是IBM DW关于Javassist一个较为完整的教程:
    http://www.ibm.com/developerworks/cn/java/j-dyn0916/
    如下的代码是动态创建Java类二进制字节码并通过反射调用的示例,可供参考:

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    import javassist.CannotCompileException;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtConstructor;
    import javassist.CtField;
    import javassist.CtNewMethod;
    import javassist.Modifier;
    import javassist.NotFoundException;
    import javassist.CtField.Initializer;
    
    public class JavassistGenerator {
    
        public static void main(String[] args) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
            // 创建类
            ClassPool pool = ClassPool.getDefault();
            CtClass cls = pool.makeClass("cn.ibm.com.TestClass");
    
            // 添加私有成员name及其getter、setter方法
            CtField param = new CtField(pool.get("java.lang.String"), "name", cls);
            param.setModifiers(Modifier.PRIVATE);
            cls.addMethod(CtNewMethod.setter("setName", param));
            cls.addMethod(CtNewMethod.getter("getName", param));
            cls.addField(param, Initializer.constant(""));
    
            // 添加无参的构造体
            CtConstructor cons = new CtConstructor(new CtClass[] {}, cls);
            cons.setBody("{name = "Brant";}");
            cls.addConstructor(cons);
    
            // 添加有参的构造体
            cons = new CtConstructor(new CtClass[] {pool.get("java.lang.String")}, cls);
            cons.setBody("{$0.name = $1;}");
            cls.addConstructor(cons);
    
            // 打印创建类的类名
            System.out.println(cls.toClass());
    
            // 通过反射创建无参的实例,并调用getName方法
            Object o = Class.forName("cn.ibm.com.TestClass").newInstance();
            Method getter = o.getClass().getMethod("getName");
            System.out.println(getter.invoke(o));
    
            // 调用其setName方法
            Method setter = o.getClass().getMethod("setName", new Class[] {String.class});
            setter.invoke(o, "Adam");
            System.out.println(getter.invoke(o));
    
            // 通过反射创建有参的实例,并调用getName方法
            o = Class.forName("cn.ibm.com.TestClass").getConstructor(String.class).newInstance("Liu Jian");
            getter = o.getClass().getMethod("getName");
            System.out.println(getter.invoke(o));
        }
    
    }

    最后需要特别注意的是:
    1. Javassist不支持要创建或注入的类中存在泛型参数
    2. Javassist对@类型的注解(Annotation)只支持查询,不支持添加或修改

    原文地址:http://blog.csdn.net/sadfishsc/article/details/9999169

  • 相关阅读:
    第三章 达瑞,一个很能挣钱的男孩
    入门代码教程第一节 如何:定义服务协定
    第二节 Windows Communication Foundation 基础概念
    入门代码教程第四节 如何:创建客户端
    BZOJ:2186: [Sdoi2008]沙拉公主的困惑
    DNN学习笔记代码学习:Provider 荣
    DNN学习笔记代码学习:DataCache 荣
    DNN学习笔记代码学习:ProviderConfiguration 荣
    DNN学习笔记代码学习:Reflection 荣
    java动态加载类
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468570.html
Copyright © 2020-2023  润新知