【发布时间】:2020-11-14 22:20:43
【问题描述】:
我有一个代理,我将其动态加载到正在运行的 Java 应用程序中,该应用程序在连接时会打开一个简单的 Swing JFrame。它还允许将新行追加到该 JFrame 内的 TextArea 中。
我的目标是改变一些方法在代理加载到的应用程序中的工作方式。
public class MyAgent {
public static void agentmain(String args, Instrumentation instrumentation) {
UI.openWindow();
UI.addMessage("Agent loaded: %s", args);
instrumentation.addTransformer(new MyTransformer());
instrumentation.redefineClasses(new ClassDefinition(Class.forName("app.TargetClass"), ...));
}
}
UI 窗口在代理可访问的另一个类中进行管理。加载代理时,它会成功打开一个窗口并附加一条文本消息。
public class UI {
private static SwingWindow swingWindow;
public static void addMessage(String format, Object... args) {
System.out.println("UI: " + String.format(format, args));
swingWindow.appendToTextArea(format, args);
}
public static void openWindow() {
try {
SwingUtilities.invokeAndWait(() -> swingWindow = new SwingWindow());
}
catch (Exception e) {}
}
}
我正在使用 Javassist 在我的转换器中生成字节码。
public class MyTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, ..., byte[] classBuffer) {
if (className.equals("app/TargetClass")) {
UI.addMessage("Now transforming the class that I need!");
try {
ClassPool classPool = ClassPool.getDefault();
CtClass targetClass = classPool.get("app.TargetClass");
CtMethod targetMethod = targetClass.getDeclaredMethod("importantMethod");
targetMethod.insertBefore("me.domain.agent.ui.UI.addMessage(\"Hello from Javassist!\")");
byte[] byteCode = targetClass.toBytecode();
targetClass.detach();
return byteCode;
}
catch (Exception e) {
UI.addMessage("Couldn't transform the class I needed.");
}
}
return classBuffer;
}
}
找到了目标类,但字节码没有编译:
UI:转换类 app.TargetClass 失败:[源错误] 没有这样的类:me$domain.agent.ui.UI
但是,UI 类在代理内部:
agent.jar
├── META-INF
└── me.domain.agent
├── ui
│ └── UI.class
├── MyTransformer.class
└── Agent.class
我已经尝试将代理的 ClassLoader 添加到 Javassist 的 ClassPool 中:
classPool.insertClassPath(new LoaderClassPath(Agent.class.getClassLoader()));
但它不起作用。如何将对代理 UI 的调用添加到字节码中?
【问题讨论】:
标签: java instrumentation javassist javaagents