使用Byte Buddy for Java Agent

use*_*817 5 java instrumentation bytecode byte-buddy

我希望创建一个代理以附加到我们的实时Tomcat和Weblogic服务器,该代理将拦截对我的公司程序包中声明的所有类的所有方法调用,并记录一些指标,例如执行时间。

我遇到了Byte Buddy库,它似乎可以满足此需求。但是,对于使用Byte Buddy创建代理的方法,我还不是100%清楚:

我采用了创建自己的代理的方法,并使用Maven对其进行了打包,以将Byte Buddy作为胖子(这样Byte Buddy代码在类路径中)包括进了我的引用catalina.bat

编辑:自从我下载了源代码,并发现AgentBuilder依赖于byte-buddy-agent包,因此上述问题无关紧要。

Tomcat可以正常启动,并且可以看到代理被调用,就像看到的“ Entered premain”一样System.out

但是,System.out当我在部署到Tomcat的单独war文件上执行代码时,从未看到“已拦截” 。 编辑:以下代码根据拉斐尔的回应进行了更新,现在可以正常工作。

有人可以告诉我在这里我可能做错了什么吗?我已经在下面包含了代理代码。

另外,有人可以告诉我哪个ElementMatchers最适合软件包匹配吗?我尝试过,nameStartsWith但是没有任何效果,API文档也没有说明它是否是完全限定的类名。

*编辑:nameStartsWith会检查软件包。*

无论如何,在此先感谢您的帮助!

package com.mycompany.agent;

import java.lang.instrument.Instrumentation;
import java.util.concurrent.Callable;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;

public class MyAgent {

public static void premain(String agentArgument, Instrumentation instrumentation) {
    System.out.println("Entered premain");
    try{
        new AgentBuilder.Default()
                .withListener( new AgentBuilder.Listener() {

                    public void onComplete(String arg0) {
                        System.out.println("Completed - " + arg0);
                    }

                    public void onError(String arg0, Throwable arg1) {
                        System.out.println("Error - " + arg0+", "+arg1.getMessage());
                        arg1.printStackTrace();
                    }

                    public void onIgnored(String arg0) {
                        System.out.println("Ignored - " + arg0);
                    }

                    public void onTransformation(TypeDescription arg0, DynamicType arg1) {
                        System.out.println("Transformed - " + arg0+", type = "+arg1);
                    }

                })
                .rebase(ElementMatchers.nameStartsWith("com.mycompany"))
                .transform(new AgentBuilder.Transformer() {
                    public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDescription) {
                        return builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(new Interceptor()));
                    }
                }).installOn(instrumentation);
    }
    catch (RuntimeException e) {
        System.out.println("Exception instrumenting code : "+e);
        e.printStackTrace();
    }

}



package com.mycompany.agent;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

@SuppressWarnings("rawtypes")
public class Interceptor {

@RuntimeType
public Object intercept( @SuperCall Callable<?> callable, @AllArguments Object[] allArguments, @Origin Method method, @Origin Class clazz) throws Exception {
    long startTime = System.currentTimeMillis();
    Object response;
    try{
        response = callable.call();
    }
    catch(Exception e) {
        System.out.println("Exception occurred in method call: " + methodName(clazz, method, allArguments) + " Exception = " + e);
        throw e;
    }
    finally{
        System.out.println("Method " + methodName(clazz, method) + " completed in " + (System.currentTimeMillis() - startTime) + " miliseconds");
    }
    return response;
}

private String methodName(Class clazz, Method method){
    return methodName(clazz, method, null);
}

private String methodName(Class clazz, Method method, Object[] allArguments){
    StringBuilder builder = new StringBuilder();
    builder.append(clazz.getName());
    builder.append(".");
    builder.append(method.getName());
    builder.append("(");
    for(int i = 0; i < method.getParameters().length; i++) {

        builder.append(method.getParameters()[i].getName());
        if(allArguments != null) {
            Object arg = allArguments[i];
            builder.append("=");
            builder.append(arg != null ? arg.toString() : "null");              
        }

        if(i < method.getParameters().length - 1) {
            builder.append(", ");
        }
    }
    builder.append(")");
    return builder.toString();
}
Run Code Online (Sandbox Code Playgroud)

Raf*_*ter 4

一切似乎都是对的。您应该始终尝试注册一个AgentBuider.Listener,如果 Byte Buddy 因发出非法检测尝试而导致异常,它将公开不成功检测的堆栈跟踪。

我假设您的类的包私有定义Interceptor是导致此异常的原因。您的拦截器必须对所有检测代码可见。否则,该类不可调用。