0

我正在尝试创建一个通用 Java 代理来检测任何 Java 应用程序的方法。我已经按照本教程https://javapapers.com/core-java/java-instrumentation/创建了一个 java 代理。java 代理应该寻找一个特定的类(我现在将它限制为一个类,因为它对我不起作用)一旦找到该类,我将使用 JavaAssist API 在每个类的开头添加一个局部变量方法并捕获当前时间。在方法的最后,我想简单地打印方法执行所花费的时间。(几乎遵循所有关于 Java 代理的典型示例。

我使用指向我创建的 Java 代理 jar 文件的 --javaagent 标志运行我的测试应用程序(使用 Vert.x 的 Web 服务器)(代码在下面)。

这适用于没有返回值和没有参数或返回/采用原始类型的方法。

但是,当一个方法返回或获取一个来自另一个类的对象(我认为尚未加载)的参数时,我会收到一个 CannotCompileException 异常,并显示该类在参数列表或返回语句中没有找到。例如,此方法的仪器有效:

@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;
        }
    }
}}
4

0 回答 0