EJB (Enterprise Java Bean)

EJB (Enterprise Java Bean)

EJB (Enterprise Java Bean)とは、トランザクション処理を意識したRMIオブジェクト(RMIを使ってアクセス可能なリモートオブジェクト)です。

サーバー上のサービス(ロジック)をRMIオブジェクトとして実装するので、クライアントからはネットワークを意識せずにそのサービス(ロジック)を利用できます。

EJBでは、RMIオブジェクトに相当するクラスをEnterprise Beanと呼び、RMIのスケルトンクラスに相当するクラスをEJBコンテナと呼びます。

さらに、EJBはいくつかの点で普通のRMIオブジェクトには無い特徴をもっています。

  1. RMIオブジェクト(Bean)をインスタンス化しているVMがダウンしても、再起動すれば直前に持っていた変数値を保持した状態で復活できる。
  2. ひとつのRMIオブジェクト(Bean)に対して同期アクセス(排他的なアクセス)を行わせることができる。
  3. あるRMIオブジェクト(Bean)を参照しているクライアントを終了し、後で別のクライアントを起動しても、同じRMIオブジェクト(Bean)をオブジェクト変数として参照することができる。
  4. 「コミット」、「ロールバック」といったトランザクション処理をRMIオブジェクト(Bean)に実行させるためのメソッドを持つ。
  5. 標準のRMIが持つレジストリサーバーよりは多少細かい検索オプションを使うことができる。

このEJBに特有の機能のほとんどはEJBコンテナによって実現されます。

一方、いわゆる「ビジネスロジック」、すなわち各Beanがサービスとして提供している処理については、各Beanの実装に任されています。

あるBeanがあるDBのあるテーブルを操作するという機能を果たすとき、SQLを使ってDBMSにアクセスする作業はBean自身が行わなければ成らず、EJBコンテナは何もしてくれません。また、更新されたデータをDBに保存(コミット)する作業もBeanが自分で行わなければなりません。EJBコンテナは「コミット要求をBeanに発行する」ことだけに責任を持ちます。

EJBのコンポーネント

業務ロジックをコード化した部品をEnterprise Beanといい、DBアクセスやトランザクション処理のために自動生成されたコードをEJBコンテナといいます。また、EJBコンテナを自動生成する機能(EJBコンテナ生成ツール)を装備したDBサーバ(あるいはTPモニタ)のことをEJBサーバといいます。

EJBのトランザクション処理について

各Beanは自分がどの程度トランザクション処理に対応したBeanなのかをEJBコンテナ生成ツールに対して宣言することができます。それを見たコンテナ生成ツールはデザインされたアプリケーションのトランザクションが正常に処理されるようなEJBコンテナのコードを生成します。

その結果、トランザクション処理のほとんどをコンテナ側で実装することになるかもしれないし、Bean側で実行することになるかもしれません。それはBeanの実装内容とコンテナがどこまで対応できるかで決まってきます。

EJB Beanインスタンスの永続性

「サーバーがいったんダウンしても復活するインスタンス」という機能は「エンティティBean」と呼ばれるBean仕様によって実現されます。

エンティティBeanでは、自分がアクセスするDBの情報とは別にオブジェクトとしての自分自身をVMの外に一時退避する機能を実現しなければなりません。その仕事はBean自身が実装する場合とコンテナが代行する場合があります。

Bean自身が自分を退避する場合は、その方法は自由です。何か特別なテーブルをDB上に持って、そこに保存しても良いし、オブジェクトの復活に必要な各種パラメータを既存のエンタープライズアプリケーションに保存させてもよい。

一方、コンテナが代行する場合は、Beanのどの変数を保存しておけばよいのかをBean側からコンテナ側に教えておき、その変数値をコンテナがDB等に保存する、という風に行われます。

最もシンプルにこの機能を作ろうとすると、BeanをそのままSerializeするという方法でもよいです。

システムの規模が大きくなってくると、ビジネスロジックを部品化・再利用する仕組みが必要となってきます。このような場合にEJBが必要となってきます。

サーブレットだけでロジックを記述しようとすると、次のデメリットがあります。

「ソフトウェアの資産化」を考えたときに大事なことは、ソフトの部品化です。開発したソフトウェアをどれだけの期間にわたり利用可能でしょうか。開発したソフトウェアは、別の開発プロジェクトにも再利用可能でしょうか。これらを考えていくと、ソフト部品化のための標準的な技術、つまりコンポーネント・モデルが必要となってきます。

それも、独自のものでなく、異なる開発プロジェクトで共通して使えるインフラとなるコンポーネント・モデルが必要です。

EJBとは、サーバ側ソフトウェアの部品化のためのコンポーネント・モデルです。このモデルを使うことで、異種システムであっても、コンポーネント相互が比較的「つながりやすく」なります。プロジェクト間でのコンポーネント流用が可能となります。

Session BeanとEntity Bean

EJBコンポーネント (Enterprise Bean) には、Session Bean と Entity Beanの2種類があります。EJBサーバの中のEJBコンテナ上で動きます。EJBコンポーネントは、原則的にはどのベンダーのEJBコンテナでも動きます。

Session Beanは利用者とのセッションごとに生成・消滅するオブジェクトです。消滅した後は何も残りません。もし、実行途中でサーバが落ちてしまうようなことがあれば、利用者がサイドサーバに入り直せばいいのです。

Entity Beanは永続的なオブジェクトです。EJBサーバがたとえ落ちても、立ち上げ後は復活します。商品情報や在庫数が消えてしまっては困るからです。これは、オブジェクト・データベースと似ています。あるいはリレーショナルデータベースのレコードと同じものと考えていただければいいです。

この違いを説明するために、例としてWebによるショッピングモールを実現するプログラムを考えてみます。

このサンプルには利用者ごとのセッションを担当するショッピングカートオブジェクトと商品オブジェクトがあります。カートは利用者が接続してくるたびに生成し、セッションが断たれれば消滅してメモリの中から消えるオブジェクトである。このカートの実現に使うのはSession Beanです。

一方、商品オブジェクトは商品情報や在庫数などのデータを管理するためのものなので、たとえサーバがダウンしても情報を保持しつづける必要があります。商品を実現させるにはEntity Beanを利用します。

EJBコンテナはインフラを提供する

Entity Beanでは永続的オブジェクトを実現するために何らかの形でデータを保存しないといけません。このデータを保持するコードはEntity Beanの中に記述することができます。データをJavaオブジェクトとして保持するだけでなく、SQLを発行して外部のデータベースに書き込むよう記述します。 この際、データベースとセッションを張り、同期を取るといったコーディングが不要である点がEntity Beanの特色です。これらのトランザクション管理に関係する機能はEnterprise Bean側でなく、EJBコンテナ側が引き受けてくれるからです。記述する側にとっては楽であり、またソフト部品としての再利用性も高まります。

ここにも、プログラムの分業があります。Enterprise Beanおしてビジネスロジックを記述するプログラマと、トランザクション管理に関わるインフラをEJBコンテナとして構築するプログラマとの分業です。

さらに、Entity Beanを呼び出すServletの側ではEntity Beanがどのようにデータ管理をしているかは関知しなくて良い。この点が再利用性を上げるための大きなポイントである。

EJBは分散サーバに適用可能

EJBコンポーネントはJava RMI(Remote Method Invocation)で呼び出します。このさい、リモートオブジェクトの入り口が必要となります。 入り口の役目をするものをEJB Homeインタフェースと呼びます。

EJBコンポーネント(Enterprise Bean)を呼び出すServletとEJBサーバは同じサーバマシン上にあってもいいし、それぞれ別のサーバマシン上にあってもよい。EJBは複数のサーバに分散したシステムに適用可能な技術です。

javax.ejb.TransactionAttribute

@TransactionAttributeアノテーションは、EJBコンテナがEJBビジネスメソッドをトランザクションコンテキスト内で呼び出すかどうかを指定する。クラス又はメソッドに指定する。

属性

ビジネスメソッドの呼び出し時に、EJBコンテナがトランザクションの境界設定を管理する方法を指定する。指定する値はTransactionAttributeTypeの定数を参照。

@TransactionAttribute(TransactionAttributeType.NEVER)
public String conclusion() {
    //
}