レベルエンター山本大のブログ

面白いプログラミング教育を若い人たちに

BLOCKVROCKリファレンス目次はこちら

Guiceを使ったAOP

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クラスのスタティック変数やメソッドが読み込まれていることにも注意してください。
GuiceAPIでみて見ると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