ModuleClassLoaderの動作解析をどのように行ったか
JBoss Advent Calendar 2012の13日目のエントリです。今日はちょっと趣向を変えて、昨日のModuleClassLoaderのエントリを書いたときにソースを眺めてから実際の動作を確認したわけですが、どのように行ったのかをメモっておきます。
JBoss Developer Studio 6というEclipseベースのIDE(コミュニティ版はJBoss Tools)が先日リリースされたので、まずネタで使ってみました。というのも、JBDS 5からなのですが、デバッガを使ったときにアプリケーションサーバ側のソースをMavenリポジトリから自動取得してステップインできるという機能が追加されていたので、それのお試し。JBoss Modules内部もスムーズにデバッグできるはずです。
warアプリでサーブレットを生成してClass.forName("org.jboss.web.rewrite.RewriteValve");と書いて、この行にブレークポイントを仕掛けてデバッグ実行します。RewriteValveはwarアプリのモジュールから参照可能な他モジュール(サーブレットコンテナ実装のjar)に含まれているクラスを適当にピックアップしました。ブレークポイントで止まったらステップインしていくと、JBoss AS7側のクラスに当たりますが、Mavenリポジトリから該当ソースのダウンロードが行われて問題なくステップインできます。便利ですね。
デバッガは変数の値とか確認し放題なのですごく便利です。が、やっぱりIDEのごちゃごちゃした画面があんまり好きではないなー、というのも再確認しました。ここまでたどり着くのに40分ほど作業してました。
というわけで自分的に正攻法、Bytemanで。最終的にクラスをロードするメソッドはModuleClassLoader.loadClassLocal()だというのはソースを眺めたときに把握しているので、そこでスタックトレースとればいいだけです。
RULE ModuleClassLoader debug CLASS org.jboss.modules.ModuleClassLoader METHOD loadClassLocal AT ENTRY IF $1 == "org.jboss.web.rewrite.RewriteValve" DO traceStack() ENDRULE
Bytemanのほうが慣れているので、作業開始してから1分もかからないでスタック取得までできました。
Stack trace for thread http-/127.0.0.1:8080-1 org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:-1) org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:73) org.jboss.modules.Module.loadModuleClass(Module.java:527) org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:182) org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:131) org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:67) java.lang.Class.forName0(Class.java:-2) java.lang.Class.forName(Class.java:169) org.apache.jsp.index_jsp._jspService(index_jsp.java:54) ...
ねっ、簡単でしょ?