Java字节码增强技术(NoClassDefFoundError)问题

本文通过一个实际案例,讲述了在使用Java Agent+ByteBuddy进行字节码增强时遇到的NoClassDefFoundError问题,详细分析了问题原因,并提供了两种解决方案:延迟类加载和自定义类加载器,最终成功解决了问题。
摘要由CSDN通过智能技术生成

目录

最近为了实现Java应用RPC调用的录制和Mock回放,需要以无侵入方式获取到RPC方法的出入参数和返回响应消息等数据,于是踏上了Java字节码增强技术的道路摸索。技术路径上选择了Java Agent + Bytebuddy框架,但是在应用实践过程中,对tomcat/dubbo/rocketmq进行类切面增强时出现了NoClassDefFoundError的问题,本文针对这个关键问题的出现原因进行分析讨论,提供相应的解决思路。

1. 演示代码工程

为了方便讨论,请先下载 演示代码工程 ,整个工程结构如下,

<pre class="prettyprint hljs markdown" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">+ phantom-core 演示基础类。
+ phantom-demo 演示web应用,这是一个简单的sprint boot应用,运行在端口18080。
+ phantom-agent 一个Java agent,里面通过ByteBuddy对指定类以无侵入方式切面增强,在演示工程中主要对Tomcat web的请求进行切面处理。
+ phantom-agent-plugin 一个增强类插件,这个是为了解决NoClassDefFoundError问题而提供的一个插件解决方案,应用于phantom-agent的TransformerV3.tranform()中,项目构建后需要复制构建包到路径/tmp/phantom-agent-plugin.jar上。

下载后,分别对项目进行构建、启动和测试,命令如下,

<pre class="prettyprint hljs tcl" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;"># 使用mvn工具编译构建
mvn clean package

# 启动演示web应用
java -jar ./phantom-demo/target/phantom-demo.jar

# 测试web请求命令
curl -X POST http://127.0.0.1:18080/api/hello

若上面的web应用启动成功,则测试web请求将会收到“hello,world”的消息响应,这个简单的测试请求已经走过web服务的完整路径。工程中的Transformer将通过java agent方式对tomcat web请求进行切面处理,获取所有http请求的执行前、执行后、执行异常相关情况并打印到日志中,tomcat切点定义为,

<pre class="prettyprint hljs css" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;"># 切点:tomcat核心类StandardHostValve的invoke方法
org.apache.catalina.core.StandardHostValve.invoke(Request request, Response response);

演示工程中Transformer类有三个,

  1. com.phantom.agent.trace.TransformerV1 :用于演示问题的复现和定位
  2. com.phantom.agent.trace.TransformerV2 :用于演示问题的解决思路1
  3. com.phantom.agent.trace.TransformerV3 :用于演示问题的解决思路2

这三个类都各自继承自ByteBuddy的AgentBuilder.Transformer接口类,实现了tranform()方法。

2. 问题复现和定位

我们先复现一下NoClassDefFoundError的问题,通过设置agent启动参数agent.transformer.version=v1,执行TransformerV1版本的类增强变换,启动命令如下,

<pre class="prettyprint hljs awk" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;"># 启动命令(加载agent)
java \
-javaagent:./phantom-agent/t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值