记一次多个Java Agent同时使用的类增强冲突问题及分析

摘要:Java Agent技术常被用于加载class文件之前进行拦截并修改字节码,以实现对Java应用的无侵入式增强。

本文分享自华为云社区《记一次多个JavaAgent同时使用的类增强冲突问题及分析》,作者:Vansittart。

站在用户的角度思考问题,与客户深入沟通,找到华州网站设计与华州网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:做网站、网站建设、企业官网、英文网站、手机端网站、网站推广、申请域名、网页空间、企业邮箱。业务覆盖华州地区。

问题背景

Java Agent技术常被用于加载class文件之前进行拦截并修改字节码,以实现对Java应用的无侵入式增强。Sermant是致力于服务治理领域的开源Java Agent框架项目。某客户在集成Sermant之前已集成了两套Java Agent:用于业务能力增强的自研Java Agent和用于链路采集的SkyWalking。该客户单独挂载自研Java Agent插件包时,字节码增强可以按照预期生效。后期引入开源SkyWalking并同时将自研Java Agent插件包和SkyWalking通过-javaagent启动参数挂载至业务应用中。使用过程中发现,两者的加载顺序会对预期的拦截点增强生效与否有直接影响。为什么会产生这种现象?该客户求助Sermant社区寻求解决多个JavaAgent的增强冲突问题,以避免类似典型问题再次出现以及顺利集成Sermant用于业务的服务治理。

笔者尝试从字节码增强的底层逻辑的角度来分析该问题的症结。

挂载多个JavaAgent的增强冲突问题

引入SkyWalking的初衷,是希望自研JavaAgent对业务的增强和SkyWalking的链路追踪能力都能正常在业务应用上生效。-javaagent参数是支持多次执行的,所以因此在启动应用时在JAVA_TOOL_OPTIONS中加上了-javaagent:/xxx/my-agent.jar和-javaagent:/xxx/skywalking-agent.jar参数。

先加载自研JavaAgent后加载SkyWalking

在测试时首先把自研JavaAgent放在前面,SkyWalking放在后面, 即-javaagent:/xxx/my-agent.jar -javaagent:/xxx/SkyWalking-agent.jar。应用启动前执行的逻辑如下图所示。按照参数的配置顺序,应该是自研JavaAgent先对业务应用的jar包中字节码进行增强,然后再由SkyWalking进行增强,最后再执行业务应用的main()方法启动应用。

然而启动后发现日志中SkyWalking抛出java.lang.UnsupportedOperationException异常,该异常对应的目标类是com.google.common.eventbus.Dispatcher$LegacyAsyncDispatcher。自研JavaAgent无异常抛出。

ERROR 2022-09-27 15:32:09:546 main SkyWalkingAgent : index=0, batch=[class com.google.common.eventbus.Dispatcher$LegacyAsyncDispatcher], types=[class com.google.common.eventbus.Dispatcher$LegacyAsyncDispatcher] 
Caused by: java.lang.UnsupportedOperationException:class redefinition failed: attempted to change superclass or interfaces
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.SkyWalking.apm.dependencies.net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Dispatcher$ForJava6CapableVm.retransformClasses(AgentBuilder.java:6910)
...12 more

本文标题:记一次多个Java Agent同时使用的类增强冲突问题及分析
分享URL:http://hbruida.cn/article/dsoioco.html