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
4.1.5 Dependency Injection
ステートレスセッションBeanに対してDependency Injectionが行われるタイミングについて述べられています。Beanインスタンスに対してビジネスメソッドやコールバックメソッドが実行される前にコンテナによってリソースや他のオブジェクトのリファレンスがInjectionされるとあります。ちょっとまとめると実行される順番はこんな感じでしょうか?
- インスタンスの生成
- Dependency Injection
- 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ページでした。