Byte-Buddy系列 - 第3讲 byte-buddy与jacoco agent冲突问题
目录
- 一、原因分析
- 二、解决方案
一、原因分析
使用byte-buddy对代码进行增强后,在通过mvn test执行测试时报如下错误:
class redefinition failed: attempted to delete a method
查看相关issue确定是因为集成了jacoco导致的:
https://github.com/raphw/byte-buddy/issues/1248
https://github.com/jacoco/jacoco/issues/1470
ByteBuddy 与 JaCoCo 同时使用时出现 class redefinition failed: attempted to delete a method
错误是由于两个 Java Agent 同时对同一个类进行修改造成的冲突。
Agent 1:jacoco agent(先执行,premain):
# 执行mvn test时的jacoco相关agent设置日志
[INFO] surefireArgLine set to
-javaagent:E:\\mavenRepo\\org\\jacoco\\org.jacoco.agent\\0.8.12\\org.jacoco.agent-0.8.12-runtime.jar
=destfile=E:\\ideaWorkspace\\my-extend\\target\\jacoco.exec,
excludes=**/config/*:**/constant/*:**/bean/**
Agent 2:byte-buddy agent(后执行,agentmain):
// 通过编程方式安装byte-buddy agent
ByteBuddyAgent.install();
具体可能的 冲突原因 如下:
- 重复的类转换: 两个 Agent 可能尝试修改相同的类
- 类转换顺序: JaCoCo 在 ByteBuddy 之前运行,造成兼容性问题
- 字节码转换限制: Java 对已转换类的再次转换有严格限制
二、解决方案
配置Jacoco插件避开 ByteBuddy 要处理的类,即在jacoco中通过<exclude/>
排除掉需要通过byte-buddy进行增强的类,避免二者对同一个类进行处理而产生冲突:
<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><configuration><excludes><!-- 排除掉需要通过byte-buddy进行增强的类 --><exclude>**/YourModifedClass</exclude></excludes></configuration>
</plugin>
我在项目中的相关pom的详细配置如下:
<build><plugins><!-- Maven surefire插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.3.1</version><configuration><parallel>classes</parallel><threadCount>2</threadCount><testFailureIgnore>false</testFailureIgnore><!-- 解决jacoco插件无法生成报告 - Skipping JaCoCo execution due to missing execution data file --><argLine>-Djdk.net.URLClassPath.disableClassPathURLCheck=true -Duser.language=zh -Duser.country=CN -Duser.timezone=Asia/Shanghai -Dfile.encoding=UTF-8 ${surefireArgLine}</argLine><excludes><!-- 排除byte-buddy相关测试类(避免多次对同一个类进行增强导致冲突) --><exclude>**/ExtendBeanMethodTest.java</exclude><exclude>**/ExtendBeanPropTest.java</exclude></excludes></configuration></plugin><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>${jacoco-maven.version}</version><configuration><excludes><exclude>**/config/*</exclude><exclude>**/constant/*</exclude><exclude>**/bean/**</exclude><!-- 额外排除掉需要通过byte-buddy进行增强的类 --><exclude>com.luo.MyModifiedObj</exclude></excludes></configuration><executions><execution><id>prepare-agent</id><goals><goal>prepare-agent</goal></goals><configuration><!-- 解决jacoco插件无法生成报告 - Skipping JaCoCo execution due to missing execution data file --><propertyName>surefireArgLine</propertyName></configuration></execution><execution><id>report</id><goals><goal>report</goal></goals></execution></executions></plugin></plugins>
</build>
注意如上配置中的maven-surefire-plugin
插件的<exclude/>
配置,我通过这段配置排除了个别测试类,避免我的多个测试都通过byte-buddy对同一个类进行处理产生冲突:
<!-- Maven surefire插件 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><excludes><!-- 排除byte-buddy相关测试类(避免多次对同一个类进行增强导致冲突) --><exclude>**/ExtendBeanMethodTest.java</exclude><exclude>**/ExtendBeanPropTest.java</exclude></excludes></configuration>
</plugin>