Javassist使用场景
与Java Agent结合实现代码增强
premain方式
定义一个类,在里面添加premain方法,之后将该类打包为jar包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class JarAgent { public static void agentmain(String args, Instrumentation instrumentation) throws Exception { premain(args, instrumentation); } public static void premain(String args, Instrumentation instrumentation) throws Exception { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.get("org.example.App"); ctClass.defrost(); CtMethod doOk = ctClass.getMethod("doOk", "()V"); doOk.insertBefore("{System.out.println(\"change class success\");}"); Class<?> redefineClass = null; Class<?> aClass = JarAgent.class.getClassLoader().loadClass("org.example.App"); Class<?>[] allLoadedClasses = instrumentation.getAllLoadedClasses(); for (Class<?> clz : allLoadedClasses) { if ("org.example.App".equals(clz.getName())) { redefineClass = clz; } } byte[] bytecode = ctClass.toBytecode(); ClassDefinition classDefinition = new ClassDefinition(redefineClass, bytecode); instrumentation.redefineClasses(classDefinition); ClassFileTransformer transformer = new CursomTransformer(); instrumentation.addTransformer(transformer); } static class CustomTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { return classfileBuffer; } }
|
同时在MANIFEST中需配置Premain-Class、Can-Redefine-Classes和Can-Retransform-Classes等信息
1 2 3 4
| Manifest-Version: 1.0 Premain-Class: org.example.JarAgent Can-Redefine-Classes: true Can-Retransform-Classes: true
|
之后在对应程序启动时,添加启动参数
agentmain方式
和premain方式类似,这里需要在类中添加agentmain方法,之后将类打包为jar包
MANIFEST中需特殊配置Agent-Class属性
之后不需要添加特殊的启动参数,直接启动目标程序
最后通过VirtualMachine的attach方法,修改目标程序中的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Main { public static void main(String[] args) throws Exception { VirtualMachine vm; while (true) { List<VirtualMachineDescriptor> list = VirtualMachine.list(); for (VirtualMachineDescriptor vmd : list) { System.out.println(vmd.displayName()); if (vmd.displayName().equals("xxx")) { VirtualMachine.attach(vmd); } } break; } vm = VirtualMachine.attach("17348"); vm.loadAgent("jaragent-1.0-SNAPSHOT.jar"); vm.detach(); }
|
如果运行该类时报错,可尝试加上启动参数-Xbootclasspath/a:,来设置运行时类的搜索路径
1
| java -Xbootclasspath/a:xxx\tools.jar Main
|