EJB 3.0(Public Draft)入門記 Simplified API Chapter 4

早起きしたので朝に書いてます。

今回からChapter 4 です。Chapter 4 はステートレスセッションBeanがお題ですが、いままでにすでに説明されいることばかりな気がします。

Chapter 4 Stateless Session Beans

4.1 Requirements for Stateless Session Bean

4.1.1 Business Interfaces

EJB 3.0のセッションビーンのビジネスインタフェースは通常のJavaインタフェースで、以前のようにEJBObjectやEJBLocalObjectインターフェースではないと言っています。

Webサービスを実装するセッションBeanに関してはWebサービスのインタフェースを定義する必要はないようです。Webサービスのオペレーションとして公開されるメソッドを識別されるためにはWebMethodアノテーションが使われるとあります。WebServiceアノテーションもあるらしいです。WebMethodアノテーションWebServiceアノテーションはJSR-181で定義されているそうです。
EJB 2.1ではセッションビーンWebサービスとして公開できてもインタフェースや定義ファイルが必要だったのをアノテーションで行えるということですね(たぶん)。
使おうと思えばJBossではこれらのアノテーションが使えるらしいです。http://www.jboss.com/jbossBlog/blog/。大雑把にしか見てないですがEJB 2.1にも使えると書いてあるような気がします。

4.1.2 Home Interfaces

ステートレスセッションBeanはホームインタフェースを必要としないとあります。
ただホームインタフェースはなくなったわけではなくEJB 2.1以前のAPIを使用しているクライアントとの互換のために使うこともできるみたいです。Chapter 10を見ると@RemoteHomeとか@LocalHomeなどのアノテーションがありました。いずれこれらのアノテーションを使ったコードを作ってみたいと思います。

4.1.3 Bean Class

ステートレスセッションBeanは@Statelessアノテーションで示されるかデプロイメント記述で定義される必要があって、EJB 2.1以前のようにjavax.ejb.SessionBeanインタフェースを実装する必要はないということです。

4.1.4 Callbacks for Stateless Session Bean

ステートレスセッションBeanでサポートされるコールバックは2つだそうです。

  • PostConstruct
    • PostConstructコールバックは、コンテナによるDependecy Injectionの実行後かつBeanに対する最初のビジネスメソッド呼び出し前に行われる。特定のトランザクションコンテキストやセキュリティコンテキスト内では実行されない。
  • PreDestroy
    • PreDestroyコールバックはBeanのインスタンスが破棄されるときに実行される。特定のトランザクションコンテキストやセキュリティコンテキスト内では実行されない。

4.1.5 Dependency Injection

ステートレスセッションBeanに対してDependency Injectionが行われるタイミングについて述べられています。Beanインスタンスに対してビジネスメソッドやコールバックメソッドが実行される前にコンテナによってリソースや他のオブジェクトのリファレンスがInjectionされるとあります。

ちょっとまとめると実行される順番はこんな感じでしょうか?

  1. インスタンスの生成
  2. Dependency Injection
  3. PostConstructコールバック

4.1.6 Interceptors for Stateless Session Bean

ステートレスセッションBeanのメソッド呼び出しに対してAroundInvokeメソッドがサポートされる、とあります。インターセプタメソッドはBeanクラスもしくはインターセプタクラスに定義することができ、Beanのビジネスメソッドの呼び出しに適用されます。

インターセプタークラスを使用した例が載っています。長いですけどコピペ(適当にフォーマットしてます)。

@Stateless
@Interceptors({
com.acme.AccountAudit.class,
com.acme.Metrics.class,
com.acme.CustomSecurity.class
})
public class AccountManagementBean implements AccountManagement {
  public void createAccount(int accountNumber, AccountDetails details) { ... }
  public void deleteAccount(int accountNumber) { ... }
  public void activateAccount(int accountNumber) { ... }
  public void deactivateAccount(int accountNumber) { ... }
  ...
}
public class Metrics {
  @AroundInvoke
  public Object profile(InvocationContext inv) throws Exception {
    long time = System.currentTimeMillis();
    try {
      return inv.proceed();
    } finally {
      long endTime = time - System.currentTimeMillis();
      System.out.println(inv.getMethod() + " took " + endTime + "milliseconds.");
    }
  }
}
public class AccountAudit {
  @AroundInvoke
  public Object auditAccountOperation(InvocationContext inv) throws Exception {
    try {
      Object result = inv.proceed();
      Auditor.audit(inv.getMethod().getName(), inv.getParameters[0]);
      return result;
    } catch (Exception ex) {
      Auditor.auditFailure(ex);
      throw ex;
    }
  }
}
public class CustomSecurity {
 @AroundInvoke
 public Object customSecurity(InvocationContext inv) throws Exception {
  doCustomSecurityCheck(inv.getEJBContext().getCallerPrincipal());
  return inv.proceed();
 }
 private void doCustomSecurityCheck(Principal caller) throws SecurityException {...}
}

この例を見るとインターセプタークラスにDIできないのは不便に感じます。(自分の実験ではインターセプタークラスにDIできませんでした、ドキュメントにはインターセプタークラスはDIをサポートしているとあるのでDIできるはずなんですが...やり方がまずかったかも。この辺よくわかっていません。)さらに、例では監査やログやセキュリティなどまさに横断的関心事をインターセプタクラスとしていますが、これらを@Interceptorsアノテーションを使っていろんなBeanクラスにアノテートしてくのははめんどくさいカンジです。設定ファイルに書きたいとこですがEJB 3.0のデプロイメント記述で指定する場合簡単に書けたりしないんでしょうか。

4.2 Client View

セッションBeanのローカルクライアントやリモートクライアントはセッションBeanのビジネスインタフェースの参照をDepedency Injectionやlookupのメカニズムを使って取得する、とあります。

4.3 Other Requirements

詳しくは「EJB Core Contracts and Requirements」(492ページ!)を見てねとなっています。


今回は特に動かして実験してないですがこれでChapter 4 を終わっちゃおうと思います。4ページでした。