2007年12月9日日曜日

JaveRebelを試す その2(Javassistと組み合わせる)

昨晩のエントリの「JavaRebelを試す」でJavaRebelを使うことでClassのDynamicLoadができますねー便利ですねーと簡単に書いたけど、内容が薄すぎて何が便利かを語りきれていないのでさらに追加。
  1. サンプルコードとしては「JavaRebelを試す」のものを使うが、ButtonをClickしたときのソースを以下のように修正する。
    label.setText(Messages.getMessage());
  2. Messages Classは以下のようなカンジで。
    public class Messages {
        public static String getMessage() {
            return "hoge";
        }
    }
  3. この辺りで実行開始。もちろん、ButtonをClickすると「hoge」とか表示される。この動作自体はどぅでも良い。
  4. 次に、JavassistをDownloadしてくる。Mavenであればpom.xmlに以下の依存を追加する。
    <dependency>
      <groupId>jboss</groupId>
      <artifactId>javassist</artifactId>
      <version>3.6.ga</version>
    </dependency>
  5. Javassistを使って既存のClassのバイトコードにAdviceを追加する処理を行うClassを作成し、実行する。ClassPoolから取得するClass名(package名)やwriteFile()する時のフォルダ名は適宜変更する。
    public class Javassist01 {
        public static void main(String[] args) {
            try {
                javassist.ClassPool classPool = javassist.ClassPool.getDefault();
                javassist.CtClass ctClass = classPool.get("shin1o.Messages");
                javassist.CtMethod ctMethod = ctClass
                        .getDeclaredMethod("getMessage");
                ctMethod
                        .insertBefore("System.out.println(\"getMessage() before\");");
                ctClass.writeFile("target/classes");
                System.out.println("weaved.");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    この例だとclassの出力先は「target/classes」になっているが、Mavenを使わずにEclipseだけなら「bin」かも、
  6. これを実行すると、既存のMessagesClassが書き換えられる(weave)。
  7. 実行中の画面でButtonをClickすると、「hoge」と表示されることは変わらないが、Eclipseの標準出力には以下のような表示がされているはず!
    JavaRebel: Reloading class 'shin1o.Messages'. getMessage() before
    JavassistでMessagesクラスのバイトコードに直接埋め込んだ、getMessage()直前の「System.out.println("getMessage() before");」がちゃんと実行されている、と。
  8. プログラムを走らせたままAOPできるって事ですーーー!便利でしょ!?
コメントを投稿