遇到一个有意思的任务:在运行时修改 class 行为.
顺理成章,把目光移到了 javassist上.
javassist是一个java class 处理工具,常用于实现动态代理.常用来在各种框架里实现代理功能.
优点:
- 0 操作class的能力
- 1 可以运行时修改class文件
- 2 广泛被依赖(hibernate,mybatis都会应用它的jar包,无需再次引用)
相关代码:
//监听 8000 端口,在启动参数里设置
//java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
HotSwapper hs = new HotSwapper(8000);
//
ClassPool cp = ClassPool.getDefault();
//获取类
String clsName = C2.C8.class.getName();
CtClass cc = cp.get(clsName);
//获取方法
CtMethod m = cc.getDeclaredMethod("getSerial");
//重写方法
m.setBody("{ return getM(); }");
//调用一次
System.out.println(C2.C8.getM());
hs.reload(clsName, cc.toBytecode());
//再调用一次
System.out.println(C2.C8.getM());
注意:
- 0 JVM 不允许一个class有多个不同版本.修改class需要注意.
- 1 需要开启JPDA支持加载class java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
- 2 开启JPDA 会影响debug
文档:
http://www.javassist.org/tutorial/tutorial.html#hotswap
If the JVM is launched with the JPDA (Java Platform Debugger Architecture) enabled, a class is dynamically reloadable. After the JVM loads a class, the old version of the class definition can be unloaded and a new one can be reloaded again. That is, the definition of that class can be dynamically modified during runtime. However, the new class definition must be somewhat compatible to the old one. The JVM does not allow schema changes between the two versions. They have the same set of methods and fields.
http://www.javassist.org/html/javassist/util/HotSwapper.html
For Java 5, java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 Note that 8000 is the port number used by HotSwapper. Any port number can be specified. Since HotSwapper does not launch another JVM for running a target application, this port number is used only for inter-thread communication. Furthermore, JAVA_HOME/lib/tools.jar must be included in the class path. Using HotSwapper is easy. See the following example: CtClass clazz = ... byte[] classFile = clazz.toBytecode(); HotSwapper hs = new HostSwapper(8000); // 8000 is a port number. hs.reload("Test", classFile);
reload() first unload the Test class and load a new version of the Test class. classFile is a byte array containing the new contents of the class file for the Test class. The developers can repatedly call reload() on the same HotSwapper object so that they can reload a number of classes. HotSwap depends on the debug agent to perform hot-swapping but it is reported that the debug agent is buggy under massively multithreaded environments. If you encounter a problem, try HotSwapAgent.
项目地址:https://github.com/jboss-javassist/javassist
官网:http://www.javassist.org/