EJB

EJBメモ

作成 2002/11/9
更新 2002/11/27

このページはEJBについてのメモです。

EJBとは?

EJBとは?

Enterprise Java Beans。

EJBのしきたりに従って、開発することで、 アプリケーションの生産性、保守性、拡張性などが向上する。

EJBコンテナがシステムレベルのサービスを行ってくれるので、 アプリケーション開発者は作りたいドメインに専念できる。 トランザクションやセキュリティを (理解すれば?)簡単な設定で実現できる。

ただ、しきたりを憶えるのが大変。敷居が高い。初期教育コストが高い。 めんどくさい。システムの信頼性も拡張性も それほど重要でない場合には逆効果。 なので、なんでもかんでも使えばOKというわけでもない。

EJBロール

EJB仕様では、EJB開発、デプロイに関わる人の役割を6つに分けている。
ロール名 説明
エンタープライズBeanプロバイダ EJBをコーディングする人
アプリケーションアセンブラ Beanプロバイダの作ったEJBに
DD上でトランザクションやセキュリティを追加する。
デプロイヤ EJBをアプリケーションサーバにデプロイし、
リソースのマッピングを行う。
システム管理者 アプリケーションサーバを管理する
EJBサーバプロパイダ EJBサーバを作る
EJBコンテナプロバイダ EJBコンテナを作る

サーバプロバイダ、コンテナプロバイダは、 アプリケーションサーバを作る人。

仕様上ロールは分かれているが、同じ人が複数のロールをこなしても可。 小さなチームだと1人4役になるでしょう。

EJBの種類

EJBにはいくつかの種類があります。

セッションBean

セッションBeanは、ビジネスプロセスをモデル化したものです。 プロセスとは、例えば、検索する、受注するなどのロジックを指します。 セッションBeanはさらに、状態をもつステートフルセッションBeanと、 状態を持たない、ステートレスセッションBeanの種類があります、

エンティティーBean

エンティティーBeanは、ビジネスエンティティーをモデル化したものです。 エンティティーとは、例えばデータベースの1テーブルだったりします。 エンティティーBeanはさらに、永続性をコンテナにまかせる、 CMP(Container Managed Persistence : コンテナ管理の永続性) と BMP(Bean Managed Persistence : Bean管理の永続性) の種類があります。

エンティティーBeanの背後がデータベースの場合、 CMPはSQLはコンテナが自動的に作ります。 BMPはプログラマがSQLを書きます。 CMPが既製品、BMPがオーダメイドという感じです。

メッセージドリブンBean

メッセージドリブンBeanは非同期メッセージを扱う場合に利用します。

セッション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とか)。

ライフサイクル

MetaData

EJBHome#getMetaData()でEJBMetaDataを取得できます。 MetaDataからホーム、リモートインターフェイスクラス名などが取得できます。 MetaDataはツールなどで利用されるようです。

Handle

Handleを使うことで、一時的にシリアライズしたEJB参照の保存が可能。 保存したHandleを他のクライアントに渡すこともできる。

EJBHomeのハンドルHomeHanleと、EJBObject用のハンドルHandleがある。 使い分けは不明。

EJB1.1 エンティティーBean

CMPとBMP

CMPは既製品、BMPはオーダーメイド。

EJB1.1 CMP

いろいろ決まりがある

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){
  }

  //...

EJB1.1 BMP

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を代入する。

Primary Keyクラス

ライフサイクル

EJB2.0 エンティティーBean

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のポータビリティを高めます。

CMP

EJBクラスにフィールドは持たず、abstractのセッタ、ゲッタを定義します。

CMR

Container Managed Relationship。テーブル間の関連をCMPで表現できます。

Querry Language

メッセージドリブンBean

よく分かってないが。。。

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へのマッピング

JNDIサブコンテキスト

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環境からしか使えない。 コンテナ違いやコンテナなしのクライアントからは 直ルックアップします。

トランザクション

ACID特性

トランザクションがトランザクションたりうる特性。
特性 説明
原子性(Atomicity)  
一貫性(Consistency)  
分離性(Isolation)  
持続性(Durability)  

トランザクション分離レベル

並列処理の問題
説明
ダーティリード 更新途中コミット前のデータが読まれる
(その後ロールバックされて、あらおかしい)
ノンリピータブルリード
ファントムリード 挿入、削除されたデータが読まれる(読まれない)

分離レベルの設定
分離レベル ダーティ
リード
ノンリピータブル
リード
ファントム
リード
説明
TRANSACTION_NONE × × × トランザクションを行わない
TRANSACTION_READ_UNCOMMITED × × ×
TRANSACTION_READ_COMMITED × ×
TRANSACTION_REPEATABLE_READ ×
TRANSACTION_SERIALIZABLE

CMTとBMT

CMTがコンテナ管理のトランザクション。 トランザクションの境界設定の方法は、 DDにトランザクション属性を記述することで行う。

BMTはBean管理のトランザクション。 トランザクションをサポートしないリソースへのアクセスや、 ステートフルセッションBeanで、トランザクション的な処理を 実装したいときに利用する。UserTransactionインターフェイスを使う。

なお、エンティティーBeanは必ずCMTらしい。

CMTのトランザクション属性

属性 説明
Required なければ作る。普通。
RequiredNew 新たに作る。
Mandatory ないとエラー。
Supports あれば使う。
NotSupported あっても使わない。
Never あったらエラー。

UserTransaction

クライアントからUserTransactionを使う例

UserTransaction ut = (UserTransaction)ctx.lookup("java:comp/UserTransaction");

ut.begin();

//...

ut.commit();

java:comp/UserTransactionは決まり文句?

SessionSynchronization

セッションBeanでCMTを実装する方法に SessionSynchronizationインターフェイスを使う方法がある。
メソッド 説明
void afterBegin()
void afterCompletion(boolean committed)
void beforeCompletion()

設定できるトランザクション属性はRequired、RequiredNew、Mandatoryのみ

分散トランザクション

セキュリティ

用語

用語 説明
認証
許可
プリンシパル(主体)
Principal
個々のユーザー
クレデンシャル
レルム

宣言的セキュリティとプログラムによるセキュリティ

セキュリティーロール

security-role security-role-ref

セキュリティIDの伝達

user-caller-identity run-as

プログラムによるセキュリティー

isCallerInRoll getCallerPrincipal

サンプル

勉強しながら作ったサンプルです。 現状、かなりいいかげん。
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。サーバーがクラッシュすると預金もふっとぶっすね。

参考