我正在尝试创建一个通用的Java代理来检测任何Java应用程序的方法。 我已经按照本教程https://javapapers.com/core-java/java-instrumentation/创建了一个java代理。 java代理应该寻找一个特定的类(我现在将它限制为一个类,因为它不适合我) 找到类后,我正在使用JavaAssist API将局部变量添加到每个方法的开头并捕获当前时间。在方法的最后,我想简单地打印执行方法所花费的时间。 (几乎遵循关于Java代理的所有典型示例。
我运行我的测试应用程序(使用Vert.x的Web服务器),其中--javaagent标志指向我创建的Java代理jar文件(代码在下面)。
这适用于没有返回值且没有参数或返回/采用基本类型的方法。
但是当一个方法返回或从另一个类中获取一个对象的参数时(我认为还没有加载)我得到一个CannotCompileException异常,该消息是该类在参数列表中或者在找不到return语句。 例如,此方法的检测工作正常:
@Override
public void start() throws Exception {
logger.debug("started thread {}", Thread.currentThread().getName());
for (int port : ports) {
HttpServer httpServer = getVertx().createHttpServer(httpServerOptions);
Router router = setupRoutes();
httpServer.requestHandler(router::accept);
logger.info("Listening on port {}", port);
httpServer.listen(port);
}
}
但是这个方法返回io.vertx.ext.web.Router:
private Router setupRoutes() {
Router router = Router.router(getVertx());
router.get(STATUS_PATH).handler(this::statusHandler);
router.route().handler(BodyHandler.create());
router.post().handler(this::handleBidRequest);
router.put().handler(this::handleBidRequest);
router.get(SLEEP_CONTROLLER_PATH).handler(this::sleepControllerHandler);
return router;
}
我得到一个异常,我的java代理的输出是:
Instrumenting method rubiconproject.com.WebServerVerticle.setupRoutes()
Could not instrument method setupRoutes error: cannot find io.vertx.ext.web.Router
这是我的java代理的代码:
import java.lang.instrument.Instrumentation;
import transformers.TimeMeasuringTransformer;
public class TimeCapturerAgent {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println(TimeCapturerAgent.class.getCanonicalName() + " is loaded...... ");
inst.addTransformer(new TimeMeasuringTransformer());
}}
package transformers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class TimeMeasuringTransformer implements ClassFileTransformer {
public TimeMeasuringTransformer() {
System.out.println("TimeMeasuringTransformer added ");
}
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(className != null && className.contains("WebServerVerticle")) {
System.out.println("Instrumenting class " + className);
return modifyClass(classfileBuffer);
}
return null;
}
private byte[] modifyClass(byte[] originalClassfileBuffer) {
ClassPool classPool = ClassPool.getDefault();
CtClass compiledClass;
try {
compiledClass = classPool.makeClass(new ByteArrayInputStream(originalClassfileBuffer));
System.out.println("Created new compiled Class " + compiledClass.getName());
} catch (IOException e) {
e.printStackTrace();
return null;
}
instrumentMethods(compiledClass);
byte [] newClassByteCode = createNewClassByteArray(compiledClass);
compiledClass.detach();
return newClassByteCode;
}
private byte[] createNewClassByteArray(CtClass compiledClass) {
byte[] newClassByteArray = null;
try {
newClassByteArray = compiledClass.toBytecode();
} catch (IOException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} finally {
return newClassByteArray;
}
}
private void instrumentMethods(CtClass compiledClass) {
CtMethod[] methods = compiledClass.getDeclaredMethods();
System.out.println("Class has " + methods.length + " methods");
for (CtMethod method : methods) {
try {
System.out.println("Instrumenting method " + method.getLongName());
method.addLocalVariable("startTime", CtClass.longType);
method.insertBefore("startTime = System.nanoTime();");
method.insertAfter("System.out.println(\"Execution Duration "
+ "(nano sec): \"+ (System.nanoTime() - startTime) );");
} catch (CannotCompileException e) {
System.out.println("Could not instrument method " + method.getName()+" error: " + e.getMessage());
continue;
}
}
}}