Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
本格的なAOPにも及ばない(らしい)が、Guiceでは簡単にそのパワーを利用することができる。 簡単に言えば、「メソッド呼び出しの前後に好きな処理を後から付け加えることができる機能」と思えばよい。 「どのような処理」をつけ加えるかは、もちろんプログラムによって自在に指定することができる。 「どのメソッド」に付け加えるかは、様々な指定方法がある。 |
|
Line 4: | Line 9: |
以下はすべてのクラス(もちろんGuiceがそのインスタンスを生成するクラス)の中の特定のアノテーションがつけられたメソッドについて、好みの処理を前後に付け加える例である。 |
|
Line 73: | Line 80: |
生成されるインスタンスはGuiceの用意した一種のプロキシであることに注意。 また、そのクラスローダは通常使われているものと変わらない。 javassist等でバイトコード操作を行って処理を付け加えた場合には、クラスローダが異なってしまうそうだが、 Guiceではそのようなことはない。 |
|
Line 75: | Line 87: |
以下では特定のクラスとそのサブクラスすべてについて、「set××」というメソッドすべてを対象とする例である。 | |
Line 152: | Line 165: |
== Matcherの指定 == 上の例から見てもわかるとおり、どのメソッドを対象とするかはbindInterceptorに指定するクラス指定とメソッド指定によって決まる。 |
AOPの使い方
本格的なAOPにも及ばない(らしい)が、Guiceでは簡単にそのパワーを利用することができる。 簡単に言えば、「メソッド呼び出しの前後に好きな処理を後から付け加えることができる機能」と思えばよい。 「どのような処理」をつけ加えるかは、もちろんプログラムによって自在に指定することができる。 「どのメソッド」に付け加えるかは、様々な指定方法がある。
簡単なサンプル
以下はすべてのクラス(もちろんGuiceがそのインスタンスを生成するクラス)の中の特定のアノテーションがつけられたメソッドについて、好みの処理を前後に付け加える例である。
import java.lang.annotation.*; import org.aopalliance.intercept.*; import com.google.inject.*; import com.google.inject.matcher.*; public class Sample { /** インターセプトするメソッドの目印となるアノテーション */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface DebugTrace {} /** インターセプト対象のメソッドを持つクラス */ public static class Greeting { @DebugTrace public void hello() { System.out.println("hello, world"); } } /** インターセプタ定義 */ public static class DebugTracer implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("before "); Object r = invocation.proceed(); System.out.println("after"); return r; } } /** テスト */ public static void main(String[]args) { Injector injector = Guice.createInjector( new AbstractModule() { protected void configure() { bindInterceptor( Matchers.any(), Matchers.annotatedWith(DebugTrace.class), new DebugTracer() ); } } ); Greeting greeting = injector.getInstance(Greeting.class); greeting.hello(); System.out.println(""); System.out.println("" + greeting.getClass()); System.out.println("" + greeting.getClass().getClassLoader()); System.out.println("" + Sample.class.getClassLoader()); } }
実行結果は以下
before hello, world after class aop.Sample$Greeting$$EnhancerByGuice$$c979486 sun.misc.Launcher$AppClassLoader@a90653 sun.misc.Launcher$AppClassLoader@a90653
生成されるインスタンスはGuiceの用意した一種のプロキシであることに注意。 また、そのクラスローダは通常使われているものと変わらない。
javassist等でバイトコード操作を行って処理を付け加えた場合には、クラスローダが異なってしまうそうだが、 Guiceではそのようなことはない。
クラスとメソッド名を指定する例
以下では特定のクラスとそのサブクラスすべてについて、「set××」というメソッドすべてを対象とする例である。
import java.lang.reflect.*; import org.aopalliance.intercept.*; import com.google.inject.*; import com.google.inject.matcher.*; public class Sample { public static class Greeting { public void hello() { System.out.println("hello, world"); } public void setHello() { System.out.println("setHello"); } } public static class SubGreeting extends Greeting { public void setHi() { System.out.println("setHi"); } } public static class GoodBye { public void setGoodsBye() { System.out.println("setGoodBye"); } } public static void main(String[]args) throws Exception { Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { this.bindInterceptor( Matchers.subclassesOf(Greeting.class), new MethodNameMatcher(), new MethodInterceptor() { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("before --- " + invocation.getMethod().getName()); Object r = invocation.proceed(); System.out.println("after --- " + invocation.getMethod().getName()); return r; } } ); } }); Greeting greeting = injector.getInstance(Greeting.class); greeting.hello(); greeting.setHello(); SubGreeting subGreeting = injector.getInstance(SubGreeting.class); subGreeting.setHi(); GoodBye goodBye = injector.getInstance(GoodBye.class); goodBye.setGoodsBye(); } public static class MethodNameMatcher extends AbstractMatcher<Method>{ public boolean matches(Method t) { if (t.getName().startsWith("set")) return true; return false; } } }
実行結果は以下
hello, world before --- setHello setHello after --- setHello before --- setHi setHi after --- setHi setGoodBye
Matcherの指定
上の例から見てもわかるとおり、どのメソッドを対象とするかはbindInterceptorに指定するクラス指定とメソッド指定によって決まる。