id:arumaniさんのところでやっていたAOPの解説をみながらGuiceを使ったAOPを触ってみる。
まずは、基本的なDIのサンプルとして以下のようなクラス構成をとります。
(GuiceによるDIの基礎編"GuiceでHelloWorld”は、KronosのHPで扱っています。まずはそちらをごらんください)
クラス | 役割 |
---|---|
Dependency | 依存性インターフェイス |
DependencyImpl | 依存性具象クラス |
Service | インジェクトポイントを持つサービスオブジェクト |
Main | 起動クラス |
MyModule | DI設定モジュール |
AOPのために作成するクラスは、以下です。
またDI基礎編"GuiceでHelloWorld”と比べると、MyModuleクラスの修正も必要です。
クラス | 役割 |
---|---|
AroundLoggingInterceptor | メソッドの呼び出し前後に標準出力ログを出すインターセプター |
AOPの実装には、「aopalliance.jar」というライブラリが必要です。
これはGuiceディストリビューションにバンドルされています。
以下は、DI基礎編"GuiceでHelloWorl"と同じ、依存性およびサービスのソースコードです。
Dependency.java
package net.kronos_jp.guice.aop; public interface Dependency { public void execute(); }
DependencyImpl.java
package net.kronos_jp.guice.aop; public class DependencyImpl implements Dependency{ public void execute() { System.out.println("Hello World"); } }
Service.java
package net.kronos_jp.guice.aop; import com.google.inject.Inject; public class Service{ private Dependency depend; public Dependency getDependency() { return depend; } @Inject public void setDependency(Dependency value) { this.depend = value; } }
MyModuleではconfigure()メソッドの中でインターセプターの追加をしています。
Staticインポートにて、Matchersクラスのスタティック変数やメソッドが読み込まれていることにも注意してください。
GuiceのAPIでみて見るとMatchersクラスのメソッドは次のようになっています。
id:iad_otomamay:20070402:p3
Matcherオブジェクトはtrue or falseを表現できます。
このオブジェクトを返すスタティックなメソッドや、
Matcherのサブクラスなどで、AOPの適用範囲を指定できるのですね。
MyModule.java
package net.kronos_jp.guice.aop; import com.google.inject.AbstractModule; import static com.google.inject.matcher.Matchers.*; public class MyModule extends AbstractModule { protected void configure() { bind(Dependency.class).to(DependencyImpl.class); bindInterceptor(any(), any(), new LoggingInterceptor()); } }
インターセプターの実装は以下のようになります。
コールバックメソッドinvoke()の引数である「methodInvocation」変数を使って、
「methodInvocation.proceed();」とすることで、インターセプト対象の処理を呼び出します。
この「methodInvocation.proceed();」の呼び出しの前後で、処理行うことによって、オブジェクトに機能を織り込むことが出来ます。
AroundLoggingInterceptor.java
package net.kronos_jp.guice.aop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class AroundLoggingInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { String methodName = methodInvocation.getMethod().getName(); System.out.println("before: " + methodName); Object obj = methodInvocation.proceed(); System.out.println("after: " + methodName); return obj; } }
実行結果
before: setDependency
after: setDependency
before: getDependency
after: getDependency
before: execute
Hello World
after: execute