簡體   English   中英

如何使用 ByteBuddy 代理處理構造函數拋出的異常?

[英]How to take the exception thrown by a constructor using a ByteBuddy agent?

我正在嘗試使用ByteBuddy (v1.7.9) java 代理記錄在方法和構造函數中拋出的每個調用、返回的對象和異常,而不干擾檢測代碼的正常功能。

我當前的代理實例是

new AgentBuilder.Default()
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .type((typeDescription, classLoader, module, classBeingRedefined, protectionDomain) -> 
                     matcher.matchesIncoming(typeDescription.getTypeName()))
                .transform((builder, typeDescription, classLoader, javaModule) -> builder
                        .visit(Advice.to(CustomAdvicer.class).on(ElementMatchers.any())))
                .installOn(inst);

我從最簡單的“顧問”開始,

public class CustomAdvicer {
    @Advice.OnMethodEnter
    public static void enter(@Advice.Origin String origin) {
        System.out.println("Entering " + origin);
    }

    @Advice.OnMethodExit(onThrowable = Throwable.class)
    public static void exit(
        @Advice.Return(typing = Assigner.Typing.DYNAMIC) @RuntimeType Object value,
        @Advice.Origin String origin,
        @Advice.Thrown Throwable thrown) {
        System.out.println("Exiting " + origin);
    }
}

但是,當我運行該程序時,我從 bytebuddy 收到一個異常:

[Byte Buddy] ERROR some.pack.Thrower [sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false]
java.lang.IllegalStateException: Cannot catch exception during constructor call for public some.pack.Thrower() throws java.lang.Exception
    at net.bytebuddy.asm.Advice.doWrap(Advice.java:515)
    at net.bytebuddy.asm.Advice.wrap(Advice.java:470)
    at net.bytebuddy.asm.AsmVisitorWrapper$ForDeclaredMethods$Entry.wrap(AsmVisitorWrapper.java:481)
    at net.bytebuddy.asm.AsmVisitorWrapper$ForDeclaredMethods$DispatchingVisitor.visitMethod(AsmVisitorWrapper.java:562)
    at net.bytebuddy.jar.asm.ClassVisitor.visitMethod(ClassVisitor.java:327)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining$RedefinitionClassVisitor.visitMethod(TypeWriter.java:3801)
    at net.bytebuddy.jar.asm.ClassReader.readMethod(ClassReader.java:1020)
    at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:698)
    at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:500)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:2941)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
    at net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder.make(RebaseDynamicTypeBuilder.java:200)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8905)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9306)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9269)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9047)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9625)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9575)
    at java.security.AccessController.doPrivileged(Native Method)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9194)
    at sun.instrument.TransformerManager.transform(Unknown Source)
    at sun.instrument.InstrumentationImpl.transform(Unknown Source)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at Main.main(Main.java:23)

那么,我應該怎么做才能記錄在 constructors 中拋出的異常,記住它不能干擾原始代碼?

順便說一下,Thrower 類是我寫的一個愚蠢的類來測試這個案例:

package some.pack;

public class Thrower {
  public Thrower() throws Exception {
    throw new Exception("By courtesy of thrower! ;)");
  }
}

問題是構造函數有一個隱式的第一條指令,它是另一個或超級構造函數的調用。 你的Thrower類實際上是這樣的:

public class Thrower {
  public Thrower() throws Exception {
    super();
    throw new Exception("By courtesy of thrower! ;)");
  }
}

如果您想將整個調用包裝在 try-catch 塊中,這將產生以下結果:

public class Thrower {
  public Thrower() throws Exception {
    try {
      super();
      throw new Exception("By courtesy of thrower! ;)");
    } catch (Exception e) {
      ...
    }
  }
}

但這在 JVM 中是不合法的,因此 Byte Buddy 不允許這樣做。 沒有一種好方法可以排除超級構造函數調用,因為這是第一次調用只是 Java 語言約定,但字節碼允許更多任意組合。 由於您無法知道一個類來自哪種語言,因此 Byte Buddy 不會在這里嘗試任何技巧,只是不允許這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM