使用Java Assist检测Java代码时出现CannotCompileException,找不到类

时间:2018-01-22 04:19:24

标签: jvm instrumentation javassist javaagents jvm-bytecode

我正在尝试创建一个通用的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;
        }
    }
}}

0 个答案:

没有答案