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());
}
}




【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述