【问题标题】:ByteBuddy agent test with gradle and JUnit5使用 gradle 和 JUnit5 进行 ByteBuddy 代理测试
【发布时间】:2021-11-10 18:43:43
【问题描述】:

当我尝试测试使用 ByteBuddy 编写的 Java 代理时,我遇到了一些奇怪的行为

代理拦截带注释的方法/类并分析它们,没什么复杂的

class ByteInstrumentationConfigurer implements BootstrapConfigurer {

    @Override
    void init(...) {
        def instrumentation = ByteBuddyAgent.install()
        new AgentBuilder.Default()
                .type(isAnnotatedWith(TimeProfiling.class))
                .transform((builder, typeDescription, classLoader, module) ->
                        builder.method(not(isAnnotatedWith(Generated))) //ignore groovy generated methods (getMetaClass, etc.)
                            .intercept(MethodDelegation.to(TimeProfilingInterceptor.class)))
                .with(stdoutToLoggerWriter.withTransformationsOnly())
                .installOn(instrumentation) 

我已经进行了一些单元测试,以验证是否调用了拦截器方法

class TimeProfilingInterceptorTest {

    static MockedStatic<TimeProfilingInterceptor> timeProfilingInterceptorMockedStatic

    static {
        //agent installation happens here
        new ByteInstrumentationConfigurer().init([:], [:])
        timeProfilingInterceptorMockedStatic = mockStatic(TimeProfilingInterceptor, CALLS_REAL_METHODS)
    }
    
    @Test
    void profilingEnabledClassLevelTest() {
        //some mocking for my classes here
        testCallingComponent.callClassLevelComponentMethod()
        timeProfilingInterceptorMockedStatic.verify(()->
                TimeProfilingInterceptor.measureAndLogExecutionTime(any(),any(),any()),times(2))
}

现在,当我使用从 IDEA 开始这个测试时,我看到,我的 2 个类被转换了

[字节好友] 转换 com.kmslh.manager.profiling.components.MethodLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@18b4aac2, null, 线程[main,5,main], 加载=假]

[字节好友] 转换 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@18b4aac2, null, 线程[main,5,main], 加载=假]

但是,如果我使用 gradle test\build 任务运行此测试 - 没有转换任何类。如果我输出完整信息 - 我看到在这种情况下类加载器是 org.codehaus.groovy.runtime.callsite.CallSiteClassLoader

[字节好友] 发现 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false] [Byte Buddy] IGNORE com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false] [Byte Buddy] 完成 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false]

不确定这是否是一个问题,但我没有想法。我还尝试将测试重写为 Java - 没有结果。

有什么建议可以试试?

UPD 1

据我所见 - 当测试从 gradle 开始时 - 没有创建 auxiliary

UPD 2

我使用-verbose:class 运行 gradle 任务,看到我的类在开始检测之前加载 [Loaded com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent from file:/C:/Users/.../build/classes/groovy/main/]

当 IDEA 运行测试时(将其打包到 jar 中并运行 jar)- 在检测之后加载类

UPD 3

[已加载 com....ClassLevelTimeProfilingComponent 来自 文件:/C:/Users/../build/classes/groovy/test/]

[已加载 com....ClassLevelTimeProfilingComponent 来自 VM_RedefineClasses]

[字节好友] TRANSFORM com....ClassLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@73d16e93,空,线程[测试 worker,5,main],loaded=true]

[已加载 com....ClassLevelTimeProfilingComponent$exposedMethod 来自 文件:/C:/Users/79270/IdeaProjects/kms-trunk/KMS-Manager/build/classes/groovy/test/]

【问题讨论】:

    标签: java gradle groovy junit5 byte-buddy


    【解决方案1】:

    从您的日志中,Gradle 测试运行的类加载器与您的示例运行的类加载器不同。因此,我假设您的匹配器对正在使用的类加载器很敏感。此外,请确保您的忽略匹配器不会在并行测试中排除类加载器。

    【讨论】:

    • 感谢您的回答。我还假设问题出在类加载器上,因为如果使用 gradle,我根本看不到 [Byte Buddy] DISCOVERY/IGNORE com.kmslh.manager.profiling.components.MethodLevelTimeProfilingComponent [ .....] 之类的东西。我挖得更深一点,我想你是在谈论这个类加载器的敏感性? ByteBuddyAgent.getInstrumentation().mTransformerManager.mTransformerList[0].mTransformer.transformations[0].matcher -&gt; classLoaderMatcher.matches == true ?但我不确定如何正确更改它。能多指点一下吗?谢谢
    • 哦,我想我错了,matches==true 是正确的,意思是“任何类加载器”,所以我不需要更改它
    • 你检查你的ignore匹配器了吗?也许您的课程已经在这里过滤了。
    • 是的,这不是问题。我尝试添加RedefinitionStrategy.RETRANSFORM,在这种情况下,据我所知-gradle 从.class 文件加载类,然后从JVM 加载的类中重新加载它,用ByteBuddy 对其进行转换,然后(在测试之前)从.class 文件中读取类反正。我已在原始帖子中将带有详细类加载的输出添加到“UPD 3”
    • 但是重新转换有帮助吗?我看到一个不同的类加载器过早触发类加载的机会。
    猜你喜欢
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 2015-01-04
    • 2016-09-20
    • 2021-06-09
    • 1970-01-01
    相关资源
    最近更新 更多