简体   繁体   English

如何使用ByteBuddy委托拦截bootstrap类方法

[英]How to use ByteBuddy delegation for intercepting bootstrap class method

I'm using java agent and bytebuddy to intercept the "read" and "write" methods in FileIOStreams. 我正在使用java agent和bytebuddy拦截FileIOStreams中的“read”和“write”方法。 A feature to implement is "to call the original methods under certain circumstances, else pass". 要实现的功能是“在某些情况下调用原始方法,否则通过”。 Due to this, I need to have full control of the invoking flow using method delegation instead of wrapping it with Advice. 因此,我需要使用方法委派来完全控制调用流,而不是使用Advice包装它。

The method interception works fine when @Morph is not there, but it does not work when I add @Morph to parameters. 当@Morph不存在时,方法拦截工作正常,但是当我将@Morph添加到参数时它不起作用。 I have tested with some other annotations: 我已经测试了一些其他注释:

adding @AllArguments, @This will not block the delegation, the method will run as my interceptor; 添加@AllArguments,@这不会阻止委托,该方法将作为我的拦截器运行;

adding @Morph, @SuperCall will block the delegation. 添加@Morph,@ SuperCall将阻止委派。 No exception will be thrown: the original method will run as what it used to be. 不会抛出任何异常:原始方法将像以前一样运行。

Here is the code I want to implement: 这是我想要实现的代码:

public static void mountAgent(Instrumentation inst) {

        new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .ignore(new AgentBuilder.RawMatcher.ForElementMatchers(nameStartsWith("net.bytebuddy.").or(isSynthetic()), any(), any()))
                .with(new AgentBuilder.Listener.Filtering(
                        new StringMatcher("java.io.FileInputStream", StringMatcher.Mode.EQUALS_FULLY)
                                .or(new StringMatcher("java.io.FileOutputStream", StringMatcher.Mode.EQUALS_FULLY)),
                        AgentBuilder.Listener.StreamWriting.toSystemOut()))
                .type(named("java.io.FileOutputStream"))
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                            TypeDescription typeDescription,
                                                            ClassLoader classLoader,
                                                            JavaModule module) {
                        return builder.method(named("write").and(not(isNative())).and(takesArgument(0, byte[].class)))
                                .intercept(MethodDelegation
                                        .withDefaultConfiguration()
                                        .withBinders(Morph.Binder.install(Morphing.class))
                                        .to(WriteInterceptor.class));
                    }})
                .installOn(inst);
    }

(Code for appending interceptors to BootstrapClassLoaderSearch is skipped) (跳过BootstrapClassLoaderSearch附加拦截器的代码)

And following is my interceptors: 以下是我的拦截器:

public interface Morphing<T> {
        T Object invoke(Object[] agrs);
    }

@SuppressWarnings("unused")
public static class WriteInterceptor {
    @RuntimeType
    public static void write(
//change the input here
            byte[] bytes,
            @AllArguments Object[] args,
            @Morph Morphing<Void> morphing
    ) throws Exception {
        if (true) {
            morphing.invoke(args);
        }
        else {
            // do something
            throw new Exception();
        }
    }
}

If the input of intercepting function is empty or only byte[] bytes, the delegation will work and Exception is thrown: 如果拦截函数的输入为空或只有byte []字节,则委托将起作用并抛出异常:

[Byte Buddy] IGNORE java.io.FileInputStream [null, module java.base, loaded=true]
[Byte Buddy] COMPLETE java.io.FileInputStream [null, module java.base, loaded=true]
[Byte Buddy] DISCOVERY java.io.FileOutputStream [null, module java.base, loaded=true]
[Byte Buddy] TRANSFORM java.io.FileOutputStream [null, module java.base, loaded=true]
[Byte Buddy] COMPLETE java.io.FileOutputStream [null, module java.base, loaded=true]

Exception: java.lang.Exception thrown from the UncaughtExceptionHandler in thread "main"

If the input is 如果输入是

byte[] bytes, @AllArguments Object[] args, @Morph Morphing morphing byte [] bytes,@ AllArguments Object [] args,@ Morph变形变形

or 要么

@AllArguments Object[] args, @Morph Morphing morphing @AllArguments Object [] args,@ Morph Morphing变形

the built-in write function is called and the output is 调用内置的写入函数,输出为

[Byte Buddy] IGNORE java.io.FileInputStream [null, module java.base, loaded=true]
[Byte Buddy] COMPLETE java.io.FileInputStream [null, module java.base, loaded=true]
[Byte Buddy] DISCOVERY java.io.FileOutputStream [null, module java.base, loaded=true]
[Byte Buddy] TRANSFORM java.io.FileOutputStream [null, module java.base, loaded=true]
[Byte Buddy] COMPLETE java.io.FileOutputStream [null, module java.base, loaded=true]

What's the reason that the delegation does not work after adding @Morph, but bytebuddy still says transform is completed? 添加@Morph后委托不起作用的原因是什么,但是bytebuddy仍然表示转换已完成? How to get the correct morphing for this case? 如何为这种情况获得正确的变形? Thank you! 谢谢!

I assume that your retransformation is already failing. 我假设你的重新转换已经失败了。 Did you try to add a listener to the retransformation process. 您是否尝试向重新转换过程添加侦听器? What does Exception: java.lang.Exception thrown from the UncaughtExceptionHandler in thread "main" mean? 什么是异常:从线程“main”中的UncaughtExceptionHandler抛出的java.lang.Exception是什么意思?

One thing that I noticed is that you do not adjust the module graph. 我注意到的一件事是你没有调整模块图。 The java.base module will not be able to see your interceptor which is most likely loaded in the unnamed module of the bootstrap loader. java.base模块将无法看到最有可能在引导加载程序的未命名模块中加载的拦截器。 Did you try to add assureReadEdgeTo in your transformation where you point to your interceptor class? 您是否尝试在转换中添加assureReadEdgeTo ,指向您的拦截器类?

Also, please note that Advice does allow you to skip or even repeat a method execution. 此外,请注意, Advice允许您跳过甚至重复方法执行。 Have a look at the javadoc of the enter or exit methods. 看看enter或exit方法的javadoc。 Typically, when instrumenting bootstrap classes advice tends to be more reliable. 通常,在检测引导类时,建议往往更可靠。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM