Jensen_Interceptor_III

NOTE(2020/09/03): この記事は2013年に書かれており、古い内容になっています。現在のGroovyの実装と異なる場合があります。

いつも、PHPのことを話している人と思っているだろう。
実は、現在の大半のお仕事は Groovy によって行われているのだよ。

ブログでは初の Groovy ネタです。1年ほど、Groovy を触っているのですが、
私のような PHPer でも (一応、Javaの経験は昔にある) すんなり触ることができる
素晴らしい言語です。

大体のことは、プログラミングGroovy で学べました。
良い本です。

今回は、Groovy の Interception についてメモです。

NOTE (2020/09/03): Groovyをホスティングしていた、Codehaus が2015年にサービス終了してしまったために、リンク切れとなっていました。現在のGroovyドキュメントに当該の記述が見つからなかったため、参考リンクとして以下を貼ります。
Internet Archive へのリンク
Interceptor のテストコード
API Doc (Interceptor)

Interception と言えば、Spring Framework なんかにある、特定のメソッドの
実行前と、実行後に何らかのロジックを仕込むアイツです。
PHP で言えば、BEAR.Sunday が、この機構を見事に持ってます。

AOP 的には、本質 (実際のロジック) でない横断的な関心事 (実行時間計測・ロギング)
は、本質とは別に実装せよ。とのことらしいです。

というわけで、実際のコードを確認。

まずは、こんなコードを用意して、GroovyConsole あたりで実行してみましょう。

class Hello {
  def name
  Hello(def name) {
    this.name = name
  }
  void sayHello() {
    println "Hello, ${name}."
  }
}

def h = new Hello("bucyou")
h.sayHello() // Hello, bucyou.

この、クラスに対して、Interceptor を差し込みます。

class Hello {
  def name
  Hello(def name) {
    this.name = name
  }
  void sayHello() {
    println "Hello, ${name}."
  }
}

class MyInterceptor implements Interceptor {
  // 前処理
  Object beforeInvoke(Object object, String methodName, Object[] argments) {
    println "beforeInvoke ${methodName}"

    null
  }

  // 自動的にメソッドを invoke する場合は true
  boolean doInvoke() { true }

  // 後処理 メソッド実行の結果を result で改変できる
  Object afterInvoke(Object object, String methodName, Object[] argments, Object result) {
    println "afterInvoke ${methodName}"

    result
  }
}

def proxy = ProxyMetaClass.getInstance(Hello);
proxy.interceptor = new MyInterceptor();

// ここは interceptor による割り込みはない
def h1 = new Hello("bucyou");
h1.sayHello();

// use を使った部分だけ interceptor により割り込み有り
proxy.use {
    def h2 = new Hello("bucyou2");
    h2.sayHello() // Hello, bucyou.
}

そうすると、出力結果としては

Hello, bucyou.
beforeInvoke ctor
afterInvoke ctor
beforeInvoke sayHello
beforeInvoke println
Hello, bucyou2.
afterInvoke println
afterInvoke sayHello

となります。メソッド名で振り分けているわけではないので、コンストラクタや
println() でも、beforeInvoke, afterInvoke が走っています。
Advisor 的なものを作れば、Groovy 単体で、十分に機能する Interceptor
実装が出来るかもしれません。

Leave a reply

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください