作成 2002/11/9
更新 2002/11/27
このページはEJBについてのメモです。
Enterprise Java Beans。
EJBのしきたりに従って、開発することで、 アプリケーションの生産性、保守性、拡張性などが向上する。
EJBコンテナがシステムレベルのサービスを行ってくれるので、 アプリケーション開発者は作りたいドメインに専念できる。 トランザクションやセキュリティを (理解すれば?)簡単な設定で実現できる。
ただ、しきたりを憶えるのが大変。敷居が高い。初期教育コストが高い。 めんどくさい。システムの信頼性も拡張性も それほど重要でない場合には逆効果。 なので、なんでもかんでも使えばOKというわけでもない。
ロール名 | 説明 |
---|---|
エンタープライズBeanプロバイダ | EJBをコーディングする人 |
アプリケーションアセンブラ | Beanプロバイダの作ったEJBに
DD上でトランザクションやセキュリティを追加する。 |
デプロイヤ | EJBをアプリケーションサーバにデプロイし、
リソースのマッピングを行う。 |
システム管理者 | アプリケーションサーバを管理する |
EJBサーバプロパイダ | EJBサーバを作る |
EJBコンテナプロバイダ | EJBコンテナを作る |
サーバプロバイダ、コンテナプロバイダは、 アプリケーションサーバを作る人。
仕様上ロールは分かれているが、同じ人が複数のロールをこなしても可。 小さなチームだと1人4役になるでしょう。
EJBにはいくつかの種類があります。
セッションBeanは、ビジネスプロセスをモデル化したものです。 プロセスとは、例えば、検索する、受注するなどのロジックを指します。 セッションBeanはさらに、状態をもつステートフルセッションBeanと、 状態を持たない、ステートレスセッションBeanの種類があります、
エンティティーBeanは、ビジネスエンティティーをモデル化したものです。 エンティティーとは、例えばデータベースの1テーブルだったりします。 エンティティーBeanはさらに、永続性をコンテナにまかせる、 CMP(Container Managed Persistence : コンテナ管理の永続性) と BMP(Bean Managed Persistence : Bean管理の永続性) の種類があります。
エンティティーBeanの背後がデータベースの場合、 CMPはSQLはコンテナが自動的に作ります。 BMPはプログラマがSQLを書きます。 CMPが既製品、BMPがオーダメイドという感じです。
メッセージドリブンBeanは非同期メッセージを扱う場合に利用します。
ステート(状態)をもつかもたないかの違い。
ステートフルの代表例はショッピングカート
ステートレスの方が、ステートフルよりパフォーマンスがよいので、 どっちでもよければ、ステートレスを選択すべき。
InitialContext context = new InitialContext(); Object object = context.lookup("HelloBean"); HelloHome home = (HelloHome)javax.rmi.PortableRemoteObject.narrow(object, HelloHome.class); Hello hello = home.create(); String message = hello.sayHello(); System.out.println(message);
InitialContextは引数なしの場合には、クラスパスからjndi.propertiesを検索する。
引数のPropertiesを指定した場合にはその値を使う。
lookupの引数にはEJBコンテナで指定したJNDI名を指定
narrowはナロー。訳すと狭める。プログラムの意味的にはクラスのタイプを保証すること。
Remote呼び指しには必須。Localインターフェイスの時には単にキャストで可。
よくあるエラーはClassCastException。
クライアントJARをクラスパスに含めていないため(スタブがないため)おこる。
スタブを動的に作成する仕組みのEJBコンテナでは、クライアントJARが不要(JBossとか)。
Handleを使うことで、一時的にシリアライズしたEJB参照の保存が可能。 保存したHandleを他のクライアントに渡すこともできる。
EJBHomeのハンドルHomeHanleと、EJBObject用のハンドルHandleがある。
使い分けは不明。
EJB1.1 エンティティーBean
CMPは既製品、BMPはオーダーメイド。
いろいろ決まりがある
public class ManBean implements EntityBean{ //フィールド //EJB1.1のCMPではフィールドはpublicである必要があります。 public String id; public String name; public int age; /** * 返り値の型は主キークラスでCreateExceptionをthrowする必要があります。 * また返り値はnullを返す必要があります。 */ public String ejbCreate(String id) throws CreateException{ this.id = id; return null; } /** * ejbCreateと同じ引数を持ちます。 */ public void ejbPostCreate(String id){ } //...
CMPと違い、データベースアクセスコードを自前で実装する。
ファインダメソッドもコード上に書く
public class ManBean implements EntityBean{ private EntityContext context; //フィールド //CMPじゃないので普通にprivate private String id; private String name; private int age; /** * 返り値の型は主キークラスでCreateExceptionをthrowする必要があります。 * また返り値は主キーを返す必要があります。 */ public String ejbCreate(String id) throws CreateException{ this.id = id; String sql = "INSERT INTO " + TABLE + "(" +ID+ ") VALUES(\"" +id+ "\")"; executeUpdate(sql); return id;//CMPじゃないので普通に主キーを返す } //...
メソッド | 説明 |
---|---|
ejbCreate | DBにINSERTし、返り値に主キーを返す |
ejbPostCreate | 依存オブジェクトなどを処理 |
ejbFindByPrimaryKey | DBからSELECTし、存在すれば主キーを返す |
その他のファインダメソッド | DBからSELECTし、主キーのコレクションを返す |
ejbLoad | DBからSELECT |
ejbRemove | DBからDELETE |
ejbStore | DBにUPDATE |
setEntityContext | コンテキストのセット |
unsetEntityContext | コンテキストのアンセット |
ejbActivate | EJBをアクティブ化する。
コンテキストから主キーを取得し、セット。 |
ejbPassivate | EJBを非アクティブ化し、リソースを開放する。
例えば主キーにnullを代入する。 |
EJB2.0では1.1からCMPの書き方がかなり変わりました。 バージョンアップというよりは別物です。
新たに導入された仕様で以下の問題を解決できます。
1.1の時の問題点 | 説明 |
---|---|
RDBテーブルの関連が簡単に表現できない | 1.1では特殊な状況でもないのに、関連を表現するためにBMPにしなければなりませんでした。
2.0ではRelationにより関連を表現できます。 CMP2.0を使うことで、自前で工夫しなくても、エイリアシングの問題を解決できます。 |
遅い | Localインターフェイスが導入されました。
結合度の高い、ひとまとまりのEJBは、EJBからEJBにLocalインターフェイスでアクセスすることで、高速になります。 また、EJBコンテナの最適化が進み、速度の向上が見られます。 最近は一般的にBMPより、コンテナが最適化可能なCMPの方が高速になります。 |
finderメソッドのクエリに移植性がない | 2.0ではQuerry Languageという共通言語で記述することにより、
EJBのポータビリティを高めます。 |
EJBクラスにフィールドは持たず、abstractのセッタ、ゲッタを定義します。
Container Managed Relationship。テーブル間の関連をCMPで表現できます。
よく分かってないが。。。
JMSのQueueを介して非同期にEJBを呼ぶ
よく使われるのは確認メール送信とか
リモート、ホームインターフェイスは不要で、 onMessage(Message)を実装するだけ
JMSメッセージングには以下の2つのモデルがある。
Point-to-Point →Queue
Publish/Subscribe →Topic
トピックのサブスクライブには以下の2つの方式がある。
恒久(Durable)
永続(Persistent)
InitialContext ctx = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory)ctx.lookup("QueueConnectionFactory"); Queue queue = (Queue)ctx.lookup("HelloQueue"); QueueConnection con = factory.createQueueConnection(); QueueSession session = con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); MapMessage message = session.createMapMessage(); message.setString("word", "hello"); QueueSender sender = session.createSender(queue); sender.send(message);接続ファクトリと接続先の2つをルックアップして使うらしい。
リソースの物理的な位置をソースコードから分離するための仕組み
項目 | DD上の記述 | 説明 |
---|---|---|
環境エントリ | env-entry | 単なる値へのマッピング |
Bean参照 | ejb-ref/ejb-local-ref | 他のEJBへのマッピング |
リソースマネージャ接続ファクトリ | resource-ref | データソース、JavaMailセッション、JMS接続、
URLリソース、レガシーリソースへのマッピング resource-refはリソースファクトリへの参照です。 例えばデータソース参照は、参照先はConnectionでなくDataSoruceです。 |
リソース環境参照 | resource-env-ref | JMS送信先やJavaMailSessionへのマッピング |
EJB | java:comp/env/ejb |
データソース | java:comp/env/jdbc |
JMS | java:comp/env/jms |
URL | java:comp/env/url |
コネクタAPI | java:comp/env/eis |
InitialContextの引数に直接JNDIを指定せず、
java:comp/env/〜にマッピングすることで、
後で(デプロイ時やEJB公開後)リソースを柔軟に変更可能。
なお、java:comp/env/〜のlookupは同じJ2EE環境からしか使えない。
コンテナ違いやコンテナなしのクライアントからは
直ルックアップします。
トランザクション
トランザクションがトランザクションたりうる特性。
特性 | 説明 |
---|---|
原子性(Atomicity) | |
一貫性(Consistency) | |
分離性(Isolation) | |
持続性(Durability) |
並列処理の問題
説明 | |
---|---|
ダーティリード | 更新途中コミット前のデータが読まれる
(その後ロールバックされて、あらおかしい) |
ノンリピータブルリード | |
ファントムリード | 挿入、削除されたデータが読まれる(読まれない) |
分離レベルの設定
分離レベル | ダーティ リード | ノンリピータブル リード | ファントム リード | 説明 |
---|---|---|---|---|
TRANSACTION_NONE | × | × | × | トランザクションを行わない |
TRANSACTION_READ_UNCOMMITED | × | × | × | |
TRANSACTION_READ_COMMITED | ○ | × | × | |
TRANSACTION_REPEATABLE_READ | ○ | ○ | × | |
TRANSACTION_SERIALIZABLE | ○ | ○ | ○ |
CMTがコンテナ管理のトランザクション。 トランザクションの境界設定の方法は、 DDにトランザクション属性を記述することで行う。
BMTはBean管理のトランザクション。 トランザクションをサポートしないリソースへのアクセスや、 ステートフルセッションBeanで、トランザクション的な処理を 実装したいときに利用する。UserTransactionインターフェイスを使う。
なお、エンティティーBeanは必ずCMTらしい。
属性 | 説明 |
---|---|
Required | なければ作る。普通。 |
RequiredNew | 新たに作る。 |
Mandatory | ないとエラー。 |
Supports | あれば使う。 |
NotSupported | あっても使わない。 |
Never | あったらエラー。 |
クライアントからUserTransactionを使う例
UserTransaction ut = (UserTransaction)ctx.lookup("java:comp/UserTransaction"); ut.begin(); //... ut.commit();
java:comp/UserTransactionは決まり文句?
セッションBeanでCMTを実装する方法に SessionSynchronizationインターフェイスを使う方法がある。
メソッド | 説明 |
---|---|
void afterBegin() | |
void afterCompletion(boolean committed) | |
void beforeCompletion() |
設定できるトランザクション属性はRequired、RequiredNew、Mandatoryのみ
用語 | 説明 |
---|---|
認証 | |
許可 | |
プリンシパル(主体)
Principal | 個々のユーザー |
クレデンシャル | |
レルム |
勉強しながら作ったサンプルです。 現状、かなりいいかげん。
session.zip | シンプルセッションBean |
cmp11.zip | シンプルCMP1.1 |
bmp11.zip | シンプルBMP1.1 |
cmp20.zip | シンプルCMP2.0 |
cmr.zip | シンプルCMR |
- | シンプルCMR 多重度 1:* |
mdbean.zip | シンプルJMS |
resref.zip | シンプルリソース参照 |
trans.zip | トランザクション属性 |
- | UserTransaction |
sec.zip | シンプルセキュリティ |
sec2.zip | シンプルセキュリティ2、シンプルEAR(clientjar+ejbjar) |
helloear.zip | 2002/12/1
シンプルEAR(war+ejbjar) ビルドがイマイチ |
handle.zip | 2002/11/26
ステートフルセッションBeanでHandleを使ってみた。 銀行預金Bean。サーバーがクラッシュすると預金もふっとぶっすね。 |