Locked History Actions

Diff for "guice/Manual/UserGuide/AOP"

Differences between revisions 1 and 2
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
To compliment dependency injection, Guice supports method interception. This feature enables you to write code that is executed each time a matching method is invoked. It's suited for cross cutting concerns ("aspects"), such as transactions, security and logging. Because interceptors divide a problem into aspects rather than objects, their use is called Aspect Oriented Programming (AOP). 依存性注入をさらに便利なものにするために(訳注:?)、Guiceはメソッドインターセプションをサポートしている。
この機能はあるメソッドが呼び出されるたびに実行される。
これは、クロスカッティングコンサーン(アスペクト)、つまりトランザクション、セキュリティ、ログインなどを行うのに適している。
インターセプターは問題をオブジェクトではなく、アスペクトに分割するため、これをアスペクト指向プログラミング(AOP)と呼ぶ。
Line 5: Line 8:
Most developers won't write method interceptors directly; but they may see their use in integration libraries like Warp Persist. Those that do will need to select the matching methods, create an interceptor, and configure it all in a module. 多くの開発者は直接メソッドインターセプターを記述することはないだろうが、Warp Persistのような統合ライブラリで使用されるのを見たことがあるかもしれない。
そこでは、マッチするメソッドの選択、インターセプターの作成と構成が必要になる。
Line 7: Line 11:
Matcher is a simple interface that either accepts or rejects a value. For Guice AOP, you need two matchers: one that defines which classes participate, and another for the methods of those classes. To make this easy, there's factory class to satisfy the common scenarios. マッチャーは値を受け入れるか拒否するかを決めるシンプルなインターフェースである。
GuiceのAOPでは、二つのマッチャーが必要であり、一つはどのクラスを参加させるかであり、もう一つはそれらのクラスのメソッドを選択するものである。
これを簡単にするために、よくあるシナリオでの利用を満足するファクトリを用意している。
Line 9: Line 15:
MethodInterceptors are executed whenever a matching method is invoked. They have the opportunity to inspect the call: the method, its arguments, and the receiving instance. They can perform their cross-cutting logic and then delegate to the underlying method. Finally, they may inspect the return value or exception and return. Since interceptors may be applied to many methods and will receive many calls, their implementation should be efficient and unintrusive.
Example: Forbidding method calls on weekends
MethodInterceptorsはマッチするメソッドが呼び出されるたびに実行される。
それらは、呼び出しを調査する機会が与えられる、メソッドそれ自身、引数、そしてメソッド呼び出し対象のインスタンスである。
そしてそれ自身のクロスカッティングロジックを実行し、実装メソッドを実行することができる。
最終的に、返り値や例外を調査して復帰する。
インターセプタは多くのメソッドに適用され多数呼び出されるので、その実装は効率的でかつ出しゃばりでないことが求められる。
Line 12: Line 21:
To illustrate how method interceptors work with Guice, we'll forbid calls to our pizza billing system on weekends. The delivery guys only work Monday thru Friday so we'll prevent pizza from being ordered when it can't be delivered! This example is structurally similar to use of AOP for authorization. == 例:週末にはメソッド呼び出しを禁止する ==
Line 14: Line 23:
To mark select methods as weekdays-only, we define an annotation: Guiceのインターセプタがどのように動作するかを示すために、週末にはピザ代金受領システムの呼び出しを禁止することにしよう。
配達要員は月曜から金曜までしか働かないので、配達できないときはピザの注文ができないようにする!
この例の構造はオーサライゼーションにAOPを使う場合によく似ている。

メソッドを「ウィークデーのみ」とマークするためのアノテーションを定義する。
Line 19: Line 32:
...and apply it to the methods that need to be intercepted: インターセプトされるメソッドに適用する。
Line 29: Line 42:
Next, we define the interceptor by implementing the org.aopalliance.intercept.MethodInterceptor interface. When we need to call through to the underlying method, we do so by calling invocation.proceed(): 次に、org.aopalliance.intercept.MethodInterceptorインターフェースを実装したインターセプターを作成する。
実装メソッドの呼び出しが必要な場合には、invocation.proceed()を呼び出すことにより実行する。
Line 42: Line 56:
Finally, we configure everything. This is where we create matchers for the classes and methods to be intercepted. In this case we match any class, but only the methods with our @NotOnWeekends annotation: 最後にすべてを構成する。
これは、インターセプトされるべきクラスとメソッドを決めるマッチャーを作成すべき場所である。
このケースでは、どのクラスでも適用するが、ただし@NotOnWeekendsアノテーション付のメソッドのみとする。
Line 51: Line 67:
Putting it all together, (and waiting until Saturday), we see the method is intercepted and our order is rejected: すべてを一緒にし(そして土曜まで待ち)、メソッドがインターセプトされて注文が拒否されることを見てみよう。
Line 60: Line 76:
== Limitations == == 制限事項 ==
Line 62: Line 78:
Behind the scenes, method interception is implemented by generating bytecode at runtime. Guice dynamically creates a subclass that applies interceptors by overriding methods. If you are on a platform that doesn't support bytecode generation (such as Android), you should use
Guice without AOP support
.
舞台裏では、メソッドインターせぷしょンはバイトコードを生成することにより実装されている。
Guiceは動的にサブクラスを作成し、メソッドをオーバライドすることによりインターセプターを適用する。
もし、バイトコード生成をサポートしていないプラットフォーム(Androidなど)の場合、AOPサポート無しでGuiceを使用しなければならない。
Line 66: Line 82:
This approach imposes limits on what classes and methods can be intercepted: このアプローチでは、インターセプト可能なクラスとメソッドに次のような制限がある。
Line 68: Line 84:
    * Classes must be public or package-private.
    * Classes must be non-final
    * Methods must be public, package-private or protected
    * Methods must be non-final
    * Instances must be created by Guice by an @Inject-annotated or no-argument constructor
 * クラスはpublicあるいはパッケージprivateでなければならない。
 * クラスはfinalであってはならない。
 * メソッドはpublic、パッケージprivate、protectedのいずれかでなくてはならない。
 * メソッドはfinalであってはならない。
 * インスタンスはGuiceが作成したものでなくてはならない。@Injectアノテーションがついている、あるいは引数無しのコンストラクタによって。
Line 74: Line 90:
It is not possible to use method interception on instances that aren't constructed by Guice.
== Injecting Interceptors ==
Guiceが生成したものではないインスタンスについてメソッドインターセプションを行うことはできない。
Line 77: Line 92:
If you need to inject dependencies into an interceptor, use the requestInjection API.
== インターセプターに注入する ==

インターセプター自体に依存性注入したい場合はrequestInjection APIを用いる。
Line 88: Line 106:
Use caution when injecting interceptors. If your interceptor calls a method that it itself is intercepting, you may receive a StackOverflowException due to unending recursion. インターセプターに注入する場合は注意する。
もしインターセプターが、インターセプトしているメソッドを呼び出してしまうと、StackOverflowExceptionが発生する。
Line 90: Line 109:
== AOP Alliance == == AOP アライアンス ==
Line 92: Line 111:
The method interceptor API implemented by Guice is a part of a public specification called AOP Alliance. This makes it possible to use the same interceptors across a variety of frameworks. Guiceによって実装されるメソッドインターセプターAPIはAOPアライアンスと呼ばれるパブリック仕様の一部である。
これにより、同じインターセプターを他複数のフレームワークにて使うことができる。

アスペクト指向プログラミング

依存性注入をさらに便利なものにするために(訳注:?)、Guiceはメソッドインターセプションをサポートしている。 この機能はあるメソッドが呼び出されるたびに実行される。 これは、クロスカッティングコンサーン(アスペクト)、つまりトランザクション、セキュリティ、ログインなどを行うのに適している。 インターセプターは問題をオブジェクトではなく、アスペクトに分割するため、これをアスペクト指向プログラミング(AOP)と呼ぶ。

多くの開発者は直接メソッドインターセプターを記述することはないだろうが、Warp Persistのような統合ライブラリで使用されるのを見たことがあるかもしれない。 そこでは、マッチするメソッドの選択、インターセプターの作成と構成が必要になる。

マッチャーは値を受け入れるか拒否するかを決めるシンプルなインターフェースである。 GuiceのAOPでは、二つのマッチャーが必要であり、一つはどのクラスを参加させるかであり、もう一つはそれらのクラスのメソッドを選択するものである。 これを簡単にするために、よくあるシナリオでの利用を満足するファクトリを用意している。

MethodInterceptorsはマッチするメソッドが呼び出されるたびに実行される。 それらは、呼び出しを調査する機会が与えられる、メソッドそれ自身、引数、そしてメソッド呼び出し対象のインスタンスである。 そしてそれ自身のクロスカッティングロジックを実行し、実装メソッドを実行することができる。 最終的に、返り値や例外を調査して復帰する。 インターセプタは多くのメソッドに適用され多数呼び出されるので、その実装は効率的でかつ出しゃばりでないことが求められる。

例:週末にはメソッド呼び出しを禁止する

Guiceのインターセプタがどのように動作するかを示すために、週末にはピザ代金受領システムの呼び出しを禁止することにしよう。 配達要員は月曜から金曜までしか働かないので、配達できないときはピザの注文ができないようにする! この例の構造はオーサライゼーションにAOPを使う場合によく似ている。

メソッドを「ウィークデーのみ」とマークするためのアノテーションを定義する。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface NotOnWeekends {}

インターセプトされるメソッドに適用する。

public class RealBillingService implements BillingService {

  @NotOnWeekends
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    ...
  }
}

次に、org.aopalliance.intercept.MethodInterceptorインターフェースを実装したインターセプターを作成する。 実装メソッドの呼び出しが必要な場合には、invocation.proceed()を呼び出すことにより実行する。

public class WeekendBlocker implements MethodInterceptor {
  public Object invoke(MethodInvocation invocation) throws Throwable {
    Calendar today = new GregorianCalendar();
    if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
      throw new IllegalStateException(
          invocation.getMethod().getName() + " not allowed on weekends!");
    }
    return invocation.proceed();
  }
}

最後にすべてを構成する。 これは、インターセプトされるべきクラスとメソッドを決めるマッチャーを作成すべき場所である。 このケースでは、どのクラスでも適用するが、ただし@NotOnWeekendsアノテーション付のメソッドのみとする。

public class NotOnWeekendsModule extends AbstractModule {
  protected void configure() {
    bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class), 
        new WeekendBlocker());
  }
}

すべてを一緒にし(そして土曜まで待ち)、メソッドがインターセプトされて注文が拒否されることを見てみよう。

Exception in thread "main" java.lang.IllegalStateException: chargeOrder not allowed on weekends!
        at com.publicobject.pizza.WeekendBlocker.invoke(WeekendBlocker.java:65)
        at com.google.inject.internal.InterceptorStackCallback.intercept(...)
        at com.publicobject.pizza.RealBillingService$$EnhancerByGuice$$49ed77ce.chargeOrder(<generated>)
        at com.publicobject.pizza.WeekendExample.main(WeekendExample.java:47)}} }

制限事項

舞台裏では、メソッドインターせぷしょンはバイトコードを生成することにより実装されている。 Guiceは動的にサブクラスを作成し、メソッドをオーバライドすることによりインターセプターを適用する。 もし、バイトコード生成をサポートしていないプラットフォーム(Androidなど)の場合、AOPサポート無しでGuiceを使用しなければならない。

このアプローチでは、インターセプト可能なクラスとメソッドに次のような制限がある。

  • クラスはpublicあるいはパッケージprivateでなければならない。
  • クラスはfinalであってはならない。
  • メソッドはpublic、パッケージprivate、protectedのいずれかでなくてはならない。
  • メソッドはfinalであってはならない。
  • インスタンスはGuiceが作成したものでなくてはならない。@Injectアノテーションがついている、あるいは引数無しのコンストラクタによって。

Guiceが生成したものではないインスタンスについてメソッドインターセプションを行うことはできない。

インターセプターに注入する

インターセプター自体に依存性注入したい場合はrequestInjection APIを用いる。

public class NotOnWeekendsModule extends AbstractModule {
  protected void configure() {
    WeekendBlocker weekendBlocker = new WeekendBlocker();
    requestInjection(weekendBlocker);
    bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class), 
       weekendBlocker);
  }
}

インターセプターに注入する場合は注意する。 もしインターセプターが、インターセプトしているメソッドを呼び出してしまうと、StackOverflowExceptionが発生する。

AOP アライアンス

Guiceによって実装されるメソッドインターセプターAPIはAOPアライアンスと呼ばれるパブリック仕様の一部である。 これにより、同じインターセプターを他複数のフレームワークにて使うことができる。