Javasssist初探(需要对Java的ClassLoader机制有一些了解)

Javassist可以用来动态生成java类,就好像js可以生成可执行的js代码一样。javassist是JBoss的一个子项目,用处的话可能是在对EJB提供支持的时候,将声称各种接口的实现类和代理类。

下面给出一个例子,在这个例子中一共有三个类:DirectLoader自定义类加载器;IAccess是接口类(我们动态生成的类要实现这个接口) ;MainTest完成主要逻辑的类,其中javassist的使用也在这里面体现。下面给出三个类的源代码。需要使用javassist的jar包程序才能运行



//--------------DirectLoader------------------------------------
import java.security.SecureClassLoader;

public class DirectLoader extends SecureClassLoader{
    
protected DirectLoader() {
        
        
super(MainTest.class.getClassLoader());
    }


    
protected Class load(String name, byte[] data) {
        
return super.defineClass(name, data, 0, data.length);
    }

}



//--------------IAccess------------------------------------
import java.util.List;

public interface IAccess{
    
public void Calculate(List InVars) throws Exception;
}



//--------------MainTest------------------------------------

import java.util.List;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;

/*
 * 本类用来演示如何使用javassist动态生成
 
*/


public class MainTest {
    
private static final CtClass[] NO_ARGS = {};

    
//private static final CtClass[] INT_ARGS = { CtClass.intType };

    
private static boolean isFirst = true;

    
// 用这个标示标记是否需要重新生成新的类。
    
// 一般情况下,我们没必要动态生成类,如果有这个必要
    
// 就说明类需要动态改动并使用,所以,这个变量是很有用的
    private static boolean needReload = true;

    
private static DirectLoader s_classLoader = new DirectLoader();

    
public MainTest() {
    }


    
public static void main(String[] args) throws Exception {
        execTest();
        execTest();
    }


    
/**
     * 执行代码
     * 
     * 
@throws Exception
     
*/

    
public static void execTest() throws Exception {
        Class clas 
= null;
        
try {
            
if (needReload) {
                clas 
= createExecClass();
            }
 else {
                clas 
= s_classLoader.loadClass("ExecVar");
            }

        }
 catch (ClassNotFoundException e) {
            System.out.println(
"没有这个类,动态生成");
            clas 
= createExecClass();
        }

        
// 使用动态生成的类,最好是使用接口。否则就只能通过反射调用其方法了
        IAccess access = null;
        
try {
            access 
= (IAccess) clas.newInstance();
        }
 catch (IllegalAccessException ex) {
            ex.printStackTrace(System.err);
            System.exit(
1);
        }
 catch (InstantiationException ex) {
            ex.printStackTrace(System.err);
            System.exit(
1);
        }

        List
<String> list = new java.util.ArrayList<String>();
        list.add(
"This is a String ");
        
// 通过借口的引用调用我们动态生成的类的
        access.Calculate(list);
    }


    
private static Class createExecClass() throws Exception {
        
// ClassPool是javasssit中的类,作用嘛,自描述的
        ClassPool pool = ClassPool.getDefault();
        CtClass clas 
= null;
        
if (!isFirst) {
            
// 如果不是第一次,就必须要将原来的类在pool中作废,
            
// 否则无法在同一个pool中生成新的类
            
// 具体做法是否正确,有待进一步考证
            pool = ClassPool.getDefault();
            clas 
= pool.get("ExecVar");
            
if (clas.isFrozen()) {
                System.out
                        .println(
"Class ExecVar is frozen,Please looking for something that can make it unfrozen!");
                
// clas.defrost();
                
//从pool中拆离这个类
                clas.detach();
            }

        }

        isFirst 
= false;

        
// 动态生成一个类
        clas = pool.makeClass("ExecVar");
        clas.addInterface(pool.get(
"IAccess"));
        
// 增加默认的构造方法
        CtConstructor cons = new CtConstructor(NO_ARGS, clas);
        cons.setBody(
";");
        clas.addConstructor(cons);

        
// 增加一个方法,参数为java.util.List,返回值是空,名字叫做Calculate,所属类是clas
        CtMethod meth = new CtMethod(CtClass.voidType, "Calculate",
                
new CtClass[] { pool.get("java.util.List") }, clas);
        
// 用这个随机数检测是否是新生成的类
        double random = Math.random();
        meth.setBody(
"System.out.println("这是一个reload测试:"+$1.get(0)+",随机数:"
                
+ random + "");");
        
// 将方法加入其中
        clas.addMethod(meth);
        
// 创建一个新的ClassLoader,以加载新的生成的类,旧的s_classLoader连同旧的
        
// ExecVar类一起被废弃
        s_classLoader = new DirectLoader();
        
return s_classLoader.load("ExecVar", clas.toBytecode());
    }

}




posted @ 2010-09-12 17:07  深夜两点  阅读(919)  评论(0编辑  收藏  举报