代理处理构造函数抛出的异常

代理处理构造函数抛出的异常

本文介绍了如何使用 ByteBuddy 代理处理构造函数抛出的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ByteBuddy (v1.7.9) java 代理记录在方法和构造函数中抛出的每个调用、返回的对象和异常,而不干扰检测代码的正常运行.

I'm trying to log every call, returned objects and exceptions thrown in methods and constructors using a ByteBuddy (v1.7.9) java agent, without iterfering with the normal functioning of the instrumented code.

我当前的代理实例是

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);

我从最简单的顾问"开始,

I have started with the simplest "advicer",

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 的异常:

However when I run the program I get an exception from 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)

那么,我应该怎么做才能记录构造函数中抛出的异常,记住它不能干扰原始代码?

So, what should I do in order to log the exceptions thrown inside constructors, bearing in mind that it must not interfere with the original code?

顺便说一下,Thrower 类是我为了测试这个案例而写的一个愚蠢的类:

By the way, the Thrower class is a silly class I wrote to test this case:

package some.pack;

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

推荐答案

问题是构造函数有一个隐式的第一条指令,它是另一个或超级构造函数的调用.你的 Thrower 类实际上是这样的:

The problem is that a constructor has an implicit first instruction which is the invocation of another or a super constructor. Your Thrower class really looks like this:

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

如果你想将整个调用包装在一个 try-catch 块中,这将产生:

If you wanted to wrap the entire call in a try-catch block, this would yield this:

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在这里没有尝试任何技巧,只是不允许它.

But this is not legal in the JVM and therefore, Byte Buddy does not allow it. There is neither a good way to exclude the super constructor call as this being the first call is only a Java language convention but byte code allows more arbitrary combinations. As you cannot know what language a class comes from, Byte Buddy does not try any tricks here and simply does not allow it.

这篇关于如何使用 ByteBuddy 代理处理构造函数抛出的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 14:23