はじめに
EJB 2.1からEJB 3.0への移行方法を説明する前に、この移行によるメリットを紹介しなければなりません。基本的に、EJB 3.0ではEJBの作成に必要なクラス、インターフェイス、および配備記述子の数が削減されています。EJB 3.0仕様では、Beanの抽象クラスの代わりに従来の普通のJava
オブジェクト(Plain Old Java Object:POJO)を使い、コンポーネントインターフェイスとホームインターフェイスの代わりに従来の普通のJavaインターフェイス(Plain Old Java Interfaces:POJI)を使うことによってEJB開発を簡易化しています。ただし、インターフェイスの指定は任意なので、必ずしも含める必要はありません。
EJB 3.0での変更点は次のとおりです。
- EJB名を指定する配備記述子「ejb-jar.xml」、Beanクラス名、インターフェイス、finderメソッド、コンテナ管理リレーションシップ(Container-Managed Relationship:CMR)、およびベンダ固有の配備記述子は必要なくなりました。これらの代わりに、Beanクラス内のメタデータアノテーションを使います。アノテーションが利用できるようになったのはJDK 5.0からなので、EJB 3.0仕様のEJBを開発する場合にはJDK 5.0が必要です。
- EJB 3.0では、EJB 2.1の
create()
メソッドとfinderメソッドの代わりに、javax.persistence.EntityManager
APIを使います。EJB 2.1では、クライアントアプリケーションはエンティティBeanオブジェクトとセッションBeanオブジェクトの参照を取得する場合にJNDI名を使いますが、EJB 3.0では@Resource
アノテーション、@Inject
アノテーション、および@EJB
アノテーションを使います。 - EJB 2.1では、エンティティBeanとセッションBeanの開発にjavax.ejbパッケージのクラスとインターフェイスを使い、セッションBeanは
SessionBean
インターフェイスを実装し、エンティティBeanはEntityBean
インターフェイスを実装していました。一方、EJB 3.0では、セッションBeanクラスとエンティティBeanクラスはPOJOで、SessionBean
インターフェイスとEntityBean
インターフェイスは実装しません。 - EJB 2.1では、セッションBeanクラスは1つ以上の
ejbCreate
メソッド、コールバックメソッド、setSessionContext
メソッド、およびビジネスメソッドを指定します。同様に、エンティティEJBは、ejbCreate()
メソッド、ejbPostCreate()
メソッド、コールバックメソッド、コンテナ管理パーシスタンス(Container-Managed Persistence:CMP)、getter CMR、setter CMR、getterメソッド、setterメソッド、およびビジネスメソッドを指定します。EJB 3.0では、セッションBeanクラスが指定するのはビジネスメソッドのみです。同様に、エンティティBeanが指定するのは、ビジネスメソッド、各種Beanプロパティのgetter/setterメソッド、およびBeanリレーションシップのgetter/setterメソッドのみです。 - EJB 2.1では、ホームインターフェイスは
javax.ejb.EJBHome
インターフェイスを拡張し、ローカルホームインターフェイスはjavax.ejb.EJBLocalHome
インターフェイスを拡張します。リモートインターフェイスはjavax.ejb.EJBObject
インターフェイスを拡張し、ローカルインターフェイスはjavax.ejb.EJBLocalObject
インターフェイスを拡張します。EJB 3.0では、ローカルインターフェイスとホームインターフェイスを指定しません。代わりにPOJIのビジネスインターフェイスを使います。セッションBeanクラスでビジネスインターフェイスが指定されないと、EJBサーバーはセッションBeanクラスからPOJIのビジネスインターフェイスを生成します。
これらの変更点を念頭に置いて、本稿ではサンプルセッションBeanとサンプルエンティティBeanをEJB 2.1からEJB 3.0に移行する場合に知っておかなければならないことを中心に詳しく説明します。
セッションBeanを移行する
EJB 2.1のサンプルセッションBeanクラスであるBookCatalogBean
には、ejbCreate
メソッド、getTitle()
ビジネスメソッド、および次のコールバックメソッドが定義されています。
// BookCatalogBean.java import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class BookCatalogBean implements SessionBean { private SessionContext ctx; public String getEdition(String title) { if(title.equals("Java & XML")) return new String("2nd edition"); if(title.equals("Java and XSLT")) return new String("1st edition"); } public void ejbCreate(){} public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(SessionContext ctx) {this.ctx=ctx;} }
EJB 3.0では、セッションBeanはメタデータのアノテーションを使ってBeanの種類を指定します。Beanがステートフルの場合は@Stateful
アノテーション、ステートレスの場合は@Stateless
アノテーションを使います。また、セッションBeanでは、コンポーネントインターフェイスとホームインターフェイスの代わりにビジネスインターフェイスを使います。ビジネスインターフェイスはPOJIで、アノテーション@Local
と@Remote
を使って、ローカルまたはリモートのいずれかを指定することができます。また、セッションBeanでは、ローカルインターフェイスとリモートインターフェイスの両方を実装することもできます。
Beanクラスでインターフェイス(ローカルまたはリモート)を指定しないと、既定ではEJBサーバーによって自動的にローカルビジネスインターフェイスが生成されます。また、@Local
アノテーションと@Remote
アノテーションを使ってインターフェイスクラスを指定することもできます。
次に示すEJB 3.0のセッションBeanは、「BookCatalogBean.java」という名前のPOJOで、前述のEJB 2.1のステートレスセッションBeanを移行したものです。@Stateless
アノテーションを使い、ローカルビジネスインターフェイスを実装し、@Local
アノテーションでローカルインターフェイスのクラス名を指定していることに注意してください。
// BookCatalogBean.java EJB 3.0 Session Bean @Stateless @Local ({BookCatalogLocal.java}) public class BookCatalogBean implements BookCatalogLocal { public String getEdition(String title) { if(title.equals("Java & XML")) return new String("2nd edition"); if(title.equals("Java and XSLT")) return new String("1st edition"); } }
また、このEJB 3.0のセッションBeanでは、EJB 2.1バージョンのコンポーネントインターフェイスとホームインターフェイスの代わりに、@Local
アノテーションを使ってアノテーションを付けてローカルビジネスインターフェイス(POJI)を使っています。
EJBセッションBeanのクライアントを移行する
EJB 2.1では、セッションBeanのクライアントはJNDI名を使ってセッションBeanオブジェクトを取得します。次に示すクライアントは、JNDI名「BookCatalogLocalHome」を使ってローカルホームオブジェクトを取得し、create()
メソッドを呼び出します。その後、クライアントは、getEdition(String)
ビジネスメソッドを使って指定されたタイトルの版の値を出力します。
import javax.naming.InitialContext; public class BookCatalogClient { public static void main(String[] argv) { try{ InitialContext ctx=new InitialContext(); Object objref=ctx.lookup( "BookCatalogLocalHome"); BookCatalogLocalHome catalogLocalHome = (BookCatalogLocalHome)objref; BookCatalogLocal catalogLocal = (BookCatalogLocal) catalogLocalHome. create(); String title="Java and XML"; String edition = catalogLocal.getEdition(title); System.out.println("Edition for Title: " + title + " " + edition); } catch(Exception e){} } }
EJB 3.0では、@Inject
アノテーション、@Resource
アノテーション、または@EJB
アノテーションを使って実装する依存性注入によって、セッションBeanオブジェクトの参照を取得します。次に示すEJB 3.0のセッションBeanのクライアントクラスは、@Inject
アノテーションを使ってBookCatalogBean
クラスを注入します。タイトルの版の値の取得には、これまでどおりgetEdition(String)
ビジネスメソッドを使います。
public class BookCatalogClient { @Inject BookCatalogBean; BookCatalogBean catalogBean; String title="Java and XML"; String edition=catalogBean.getEdition(edition); System.out.println("Edition for Title: " + title + " " + edition); }