BTrace附着Glassfish容器时抛出未启动异常的问题咨询
我之前也碰到过Glassfish和BTrace整合的类似问题,结合你提供的堆栈和场景,给你拆解下问题根源和解决方案:
问题到底出在哪?
从你贴的堆栈跟踪能看到,异常是BTrace在执行retransformLoaded(重新转换已加载类)的时候触发的。具体路径是:BTrace的ClassInfo.loadExternalClass调用了Glassfish的WebappClassLoader.getResourceAsStream,而这个类加载器会强制检查Web容器的启动状态——哪怕你的Web应用已经能处理HTTP请求,容器内部的类加载器可能还没完成所有初始化标记,这时候BTrace的类遍历操作就撞在了这个检查上。
简单说:Web应用对外可用 ≠ Glassfish内部的Web类加载器完全初始化完成,BTrace的提前遍历触发了类加载器的未启动校验。
可行的解决方案
1. 等Glassfish彻底启动后再附着BTrace
别着急刚看到Web应用就绪就跑BTrace,多等几分钟,直到Glassfish日志里出现类似Web application [your-app-name] is ready to serve requests的完整启动日志,再执行BTrace附着命令。这是最稳妥的方式,避免类加载器处于中间状态。
2. 让BTrace跳过已加载类的转换
你的脚本是监听java.lang.Throwable的构造,其实不需要对已经加载的类做retransform——只需要跟踪后续新抛出的异常就行。启动BTrace时加上-n参数(no retransform):
btrace -v -n <glassfish-pid> OnThrow.java
这样BTrace不会去遍历所有已加载的Web应用类,也就不会触发WebappClassLoader的状态检查,自然不会抛出这个异常。
3. 调整Glassfish类加载器的委托模式(可选)
修改Glassfish域的domain.xml,找到你部署的Web应用对应的class-loader配置,添加delegate="true":
<application name="your-app" location="your-app.war" context-root="/your-app"> <class-loader delegate="true"/> </application>
这个配置让Web类加载器先委托父类加载器处理类加载请求,减少触发内部状态检查的概率,但不建议在生产环境随便改,可能影响应用的类加载顺序。
验证方式
用-n参数启动BTrace后,手动触发一个异常(比如在你的REST接口里写个抛出RuntimeException的逻辑),如果BTrace能正常输出异常堆栈,说明问题解决了。如果还是不行,就再等一会儿,确保Glassfish完全启动后再试。
内容的提问来源于stack exchange,提问作者maciek

