代码之家  ›  专栏  ›  技术社区  ›  dvelopp

Byte Buddy的方法委派导致StackOverflower错误

  •  2
  • dvelopp  · 技术社区  · 6 年前

    //Agent code before...
    private static void instrument(String agentOps, Instrumentation inst) {
        new AgentBuilder.Default().with(new Eager())
                .ignore(ElementMatchers.nameContains("com.dvelopp.agenttest"))
                .or(ElementMatchers.hasAnnotation(ElementMatchers.annotationType(ElementMatchers.nameContains("SpringBootApplication"))))
                .type((ElementMatchers.any()))
                .transform((builder, typeDescription, classLoader, module) -> builder.method(ElementMatchers.any())
                        .intercept(MethodDelegation.to(Interceptor.class)))
                .installOn(inst);
    }
    //Agent code after...
    

    拦截器:

    public static class Interceptor {
    
        @RuntimeType
        public static Object intercept(@SuperCall Callable<?> superCall, @SuperMethod Method superMethod, @Origin Method currentMethod,
                                       @AllArguments Object[] args, @This(optional = true) Object me) throws Exception {
            //... logic
            Object call = superCall.call();
            //... logic
            return call;
        }
    }
    

    它在一个简单的控制台应用程序上运行得非常完美。但是,当我的类路径中有一些公共库(例如简单的Spring启动项目)时,它就不能像预期的那样工作。它会产生不同的错误,但大多数错误都与以下意外反射有关:

    Exception in thread "main" java.lang.NoClassDefFoundError: sun/reflect/GeneratedMethodAccessor24
    at sun.reflect.GeneratedMethodAccessor24.<clinit>(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:403)
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
    at sun.reflect.MethodAccessorGenerator.generateMethod(MethodAccessorGenerator.java:75)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:53)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:85)
    at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:60)
    at org.apache.commons.logging.LogAdapter$Log4jLog.<clinit>(LogAdapter.java:135)
    at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog$original$snrPR67N(LogAdapter.java:102)
    at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog$original$snrPR67N$accessor$5P1QZaof(LogAdapter.java)
    at org.apache.commons.logging.LogAdapter$Log4jAdapter$auxiliary$pVmPc64S.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
    at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java)
    at org.apache.commons.logging.LogAdapter.createLog$original$4Ty3vM8s(LogAdapter.java:79)
    at org.apache.commons.logging.LogAdapter.createLog$original$4Ty3vM8s$accessor$z3gv7aJK(LogAdapter.java)
    at org.apache.commons.logging.LogAdapter$auxiliary$6cBoraQE.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
    at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java)
    at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7(LogFactory.java:67)
    at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7$accessor$VdtqA6Wx(LogFactory.java)
    at org.apache.commons.logging.LogFactory$auxiliary$ak9XEBl0.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java)
    at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7(LogFactory.java:59)
    at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7$accessor$VdtqA6Wx(LogFactory.java)
    at org.apache.commons.logging.LogFactory$auxiliary$8JhBdK8k.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java)
    at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:194)
    at hello.Application.main(Application.java:15)
    Caused by: java.lang.ClassNotFoundException: sun.reflect.GeneratedMethodAccessor24
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 39 more
    

    如我所见,这些错误发生在作为代理的对象上:

    e.g. org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7
    

    @SuperMethod Method superMethod, @Origin Method currentMethod
    

    有没有一种方法可以让委托与这些对象一起工作?

    补充:

    在这个SpringBoot2示例中( https://spring.io/guides/gs/spring-boot/

    java.lang.StackOverflowError: null
    at com.dvelopp.agenttest.MethodCallContext.getCaller(MethodCallContext.java:18)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:108)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
    at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
    at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Serhii    6 年前

    您似乎使用了错误的注释或功能。

        @RuntimeType
        public static Object intercept(@SuperCall Callable<?> superCall, @SuperMethod Method superMethod, @Origin Method currentMethod,
                                       @AllArguments Object[] args, @This(optional = true) Object me) throws Exception {
            return superCall.call();
        }
    

    下一个:

        @RuntimeType
        public static Object intercept(@RuntimeType Object value) throws Exception {
            return value;
        }
    

    在这种情况下,您避免了递归调用,但可能会有机会检测和分析不同的问题,这是明确的,并且与您的情况有关。

    可能你们也应该注意概念问题。你知道的 java 开发人员使用 Callable 对象不应使用 call() 直接地

    以下API描述用于 @RuntimeType callable null 这可能导致你的异常,不是吗?)?