java—在bytebuddy代理之前,是否有任何方法可以对加载的类方法提供建议?

iqxoj9l9  于 2021-06-27  发布在  Java
关注(0)|答案(2)|浏览(567)

我实现了一个简单的代理,如下所示。它适用于我的自定义foo.class,但我无法为java.net.url类分配建议。
测试代码示例;

public class AgentTest {

    @Test
    public void advice() throws IOException {
        Foo foo = new Foo();
        File temp = Files.createTempDirectory("tmp").toFile();
        Map<TypeDescription, byte[]> map = new HashMap<>();
        map.put(new TypeDescription.ForLoadedType(URL.class), ClassFileLocator.ForClassLoader.read(URL.class));
        ClassInjector.UsingInstrumentation.of(temp, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, ByteBuddyAgent.install()).inject(map);

        new AgentBuilder.Default()
                .disableClassFormatChanges()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(AgentBuilder.TypeStrategy.Default.REBASE)
                .type(is(URL.class).or(is(Foo.class)))
                .transform(
                        new AgentBuilder.Transformer.ForAdvice()
                                .advice(
                                        isMethod().and(isPublic()).and(named("openConnection")).or(named("myMethod")),
                                        FooAdvice.class.getName()
                                )
                )
                .installOnByteBuddyAgent();

        foo.myMethod();
    }

    public static class FooAdvice {

        @Advice.OnMethodEnter
        public static void enter() {
            System.out.println("1- method entered !");
        }

        @Advice.OnMethodExit
        public static void exit() {
            System.out.println("2- method exited");
        }
    }
}

是否有任何特定的方法来绑定在bytebuddy代理之前加载的java.net.url类方法?

yhived7q

yhived7q1#

默认情况下,byte-buddy忽略引导和扩展/平台加载程序。您需要将一个自定义的忽略匹配器设置为instrumenturl。
注意,如果您插入byte-buddy自己需要的类,尤其是byte-buddy在另一个类的插入过程中自己加载这些类时,这可能会导致麻烦。

8dtrkrch

8dtrkrch2#

拉斐尔是对的,和往常一样。不过,我想对您的问题进行更详细的阐述:您在这里遇到了一个自举问题:
建议需要在引导类路径上,否则不能与引导类一起使用 URL .
由于注解的原因,建议需要bytebuddy。所以bb也必须在引导类路径上。
如果您将示例代码放在一个类中,并且从那里使用bb代理库,那么这个类也需要位于引导类路径上。i、 如果你想运行这个代码

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;

import static net.bytebuddy.matcher.ElementMatchers.*;

class AgentTest {
  public static void main(String[] args) throws IOException {
    ByteBuddyAgent.install();
    new AgentBuilder.Default()
      .disableClassFormatChanges()
      .ignore(none())
      .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
      .with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
      .with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
      .with(AgentBuilder.InstallationListener.StreamWriting.toSystemError())
      .type(is(URL.class).or(is(Foo.class)))
      .transform(
        new AgentBuilder.Transformer.ForAdvice()
          .advice(
            isMethod().and(isPublic()).and(named("openConnection")).or(named("myMethod")),
            FooAdvice.class.getName()
          )
      )
      .installOnByteBuddyAgent();

    new Foo().myMethod();
  }

  public static class Foo {
    public void myMethod() throws IOException {
      new URL("https://google.de").openConnection();
    }
  }

  public static class FooAdvice {
    @Advice.OnMethodEnter
    public static void enter(@Advice.Origin Method method) {
      System.out.println("Entering " + method);
    }

    @Advice.OnMethodExit
    public static void exit(@Advice.Origin Method method) {
      System.out.println("Exiting " + method);
    }
  }

}

您需要在java命令行中添加如下内容:

java -Xbootclasspath/a:/path/to/my-classes;/path/to/byte-buddy-1.10.13.jar;/path/to/byte-buddy-agent-1.10.13.jar ... AgentTest

然后得到这个输出:

[Byte Buddy] BEFORE_INSTALL net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer@27bc2616 on sun.instrument.InstrumentationImpl@3941a79c
[Byte Buddy] REDEFINE BATCH #0 [2 of 2 type(s)]
[Byte Buddy] TRANSFORM AgentTest$Foo [null, null, loaded=true]
[Byte Buddy] TRANSFORM java.net.URL [null, null, loaded=true]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 2 types [0 failed batch(es)]
[Byte Buddy] INSTALL net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer@27bc2616 on sun.instrument.InstrumentationImpl@3941a79c
Entering public void AgentTest$Foo.myMethod() throws java.io.IOException
Entering public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Entering public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Exiting public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Entering public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Entering public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Exiting public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Exiting public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Exiting public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
Exiting public void AgentTest$Foo.myMethod() throws java.io.IOException

另一种方法是,您可以使用springboardjava代理,它可以动态地将bb和您的转换器放到引导类路径上,而不直接引用它们的任何类。随后可以通过反射启动转换。

相关问题