[索引]
EJBとは何か |
EJBの構成 |
EJBの種類 |
分散オブジェクト |
保存/復元機能 |
リソース管理 |
EJBの動作 |
EJBの採用指針

EJBはEnterprise JavaBeansの略で、そのまま訳すと企業用のJavaBeansと言うことになります。 ではJavaBeansとは何でしょうか。
それはJavaのコンポーネント(部品)化のためのある種の技術(仕様)のことです。 Beanは豆という意味ですが、出来上がった部品群をJavaのコーヒー豆に見立てて名づけられました。 通常、JavaBeansはその仕様に基づいて作られた個々のプログラムのことを指します。
一方、EJBは出来上がった部品(Enterprise Bean)というよりむしろ、それをうまく動作させるための仕組み一式(ミドルウェア)が主役であり、技術的な内容もJavaBeansとはまったく異なります。 EJBはJavaBeansの「内容」ではなく、部品化という「狙い」を受け継いで命名されたものと言えます。
EJBでは部品化を実現するために共通なインターフェース規約を定めています。 Enterprise Beanはこのインターフェース規約を守って作られますので、ある会社が作ったEnterprise Beanを別の会社が購入して使うことができます。
EJBは、図に示すような「低レベル」な処理を引き受けています。 したがってEnterprise Beanの開発者はビジネスロジックだけに専念することができます。

EJBを動作させるソフトウェア全体をEJBサーバと言います。 サーバと言ってもハードウェアではないので注意してください。 EJBサーバでEJBを動作させる部分(エンジン)がEJBコンテナ、その中で動く個々のプログラムがエンタープライズビーンです。
EJBはJavaを開発した米国Sun Microsystems社が提唱しました。 Sunが定めた仕様で多くのベンダーがEJBサーバを提供しています。
アプリケーション開発者が作る個々のプログラムがエンタープライズビーンです。 エンタープライズビーンは必ず他のプログラムから呼び出されて動きます。 呼び出すプログラムをEJBクライアントアプリケーションといいます。 EJBのクライアントアプリケーションとしては、サーブレット、JSP、アプレットなどがあります。
(注) クライアントとは、EJBから見てクライアント側と言う意味であり、ハードウェアとしてのクライアント上で動作するアプリケーションとは限りません。

エンタープライズビーンにはセッションビーン、エンティティビーン、メッセージ駆動型ビーンの3種類があります。 セッションビーンは、一般のビジネスロジックを実行するプログラムです。 通常はクライアントアプリケーションから呼び出されます。 セッションビーンには前回のやりとりを覚えているステートフルセッションビーンと、覚えていないステートレスセッションビーンとがあります。
エンティティビーンは、データベースを扱うプログラムで、通常はセッションビーンから呼び出されます。 プログラマーが、エンティティビーン上のデータ項目を操作するつもりでコーディングすると、コンテナがデータベースの実テーブルへのアクセスをしてくれます。
エンティティビーンにはCMP(Container Managed Persistence:コンテナ管理による永続化)とBMP(Bean Managed Persistence:ビーン管理による永続化)があります。
メッセージ駆動型ビーンは非同期メッセージを処理するものです。 セッションビーンやエンティティビーンは、同期型なのでビーンのメソッドを呼び出すと処理が終了するまで待たされます。 しかし、メッセージ駆動型ビーンでは処理の終了を待たずに、すぐに制御が返されます。

以下にEJBのいくつかの機能とその動作を説明します。 まず最初は分散オブジェクトを実現する機能です。 ここでオブジェクトとはメモリ上に展開されたJavaのプログラムのことと考えてさしつかえありません。
分散オブジェクトとは、複数のサーバ間でオブジェクト同士がメッセージ通信を行うための技術です。 ネットワークを介して異なるマシン上にあるオブジェクトが、分散オブジェクト技術によって、あたかも同一のマシンにあるかのようにプログラムすることができます。 分散オブジェクトの実現はEJBの最も重要な機能の1つです。 以下に分散オブジェクトを実現する原理を示します。
分散オブジェクトの説明のために、人の氏名と年齢を保持して、要求に応じてそれらを返すPersonというクラス(プログラム)を考えます。 氏名や年齢を返す個々のルーチン(プログラム)をJavaではメソッドと言いますが、Personとその呼出元が同一マシン上にあるときは、上図のようにしてメソッドを簡単に呼び出すことができます。 しかし呼び出し元とPersonが別のマシンに分散配置された場合、両者は通信回線(インターネットなど)で接続されるため、通信回線を介してデータがやりとりできるような工夫が必要になります。 EJBではこれをRMI(Remote Method Invocation:リモートメソッド呼び出し)と言う仕組みで実現します。

図の上部で同一マシン上にあった2つのオブジェクトが、別のマシンに分かれてRMIで動作する時の構成が図の下部です。 以下この図に沿ってRMIの動作を示します。
(1) クライアント側とサーバ側でそれぞれ相手の代理をする代理オブジェクトを生成します。 これらはrmic(rmiコンパイラ)を使って自動的に生成されます。 クライアント側をスタブ、サーバ側をスケルトンと言います。
(2) スタブはPersonへの仲介役としてメソッド呼び出しを受け取り、ネットワークを介してサーバに送信します。
(3) スケルトンは、それを受け取るとメソッド呼び出しを組み立てPersonを呼びます。
(4) Personにはローカルの呼び出し元から呼ばれたように見えます。 処理結果を返します。
(5) データは再びネットワークを介してスタブに送られ、スタブは呼び出し元にデータを渡します。
このようにしてRMIでは元のプログラムには手を加えず、異なるマシン間でやりとりさせることができます。
RMIではデータを別のマシンに送信できる形に直す必要があります。 これをシリアライズまたはマーシャリングといいます。 一般にはすべてのデータが直列化できるとは限らず、その場合にはRMIでやりとりすることはできません。
現存の主要な分散オブジェクトには、Java RMIの他にCORBA IIOPやMicrosoft .NETなどがあります。 これらはそれぞれ異なるネットワークプロトコル(通信規約)を使っています。 RMIでは、代理オブジェクト間の通信は通常はJava固有のプロトコルであるJRMP(Java Remote Method Protocol)が使われますが、他のプラットフォームと接続するためRMI-IIOPというプロトコルも準備されています。

分散オブジェクトを実現するには、相手がどのマシンにいるかを知る必要があります。 一番簡単なのはプログラムに相手のアドレスを直接書いておく(ハードコーディグ)方法ですが、そうすると相手の場所が変わるたびにプログラムを変更してコンパイルし直さねばなりません。
それでは位置情報をプログラムではなく、テーブルに持つようにしてはどうでしょうか。 この方式はハードコーディグよりは優れています。 しかし相手の場所が変わると、そことの通信を望んでいる全てのマシンのテーブルを変更しなければなりません。 そこで考え出されたのがネーミングサービスです。
ネーミングサービスとは分散環境に配置された分散オブジェクトやリソースの位置を知らせるサービスのことです。 Javaでは、ネーミングサービスにアクセスするためのインターフェースとして、JNDI(Java Naming and Directory Interface)が提供されています。
ネーミングサービスは多くの分散オブジェクトサービスで使われます。 EJBではネーミングサービスへの検索手段としてJNDIの使用を義務づけています。 JNDIはJ2EEの構成要素の1つで、名前などからオブジェクトを特定しアクセスできるようにする機構です。

EJBの第二の機能として保存/復元機能を説明します。 この機能は通常はデータベース(DB)に格納することで実現します。 この機能はパーシステンスを直訳して永続化と言われることもあります。
DBへのアクセスはSQL文を使いますが、SQLの仕様とその指示で動作するRDBは永い期間かけて改良が進められて来た完成された技術です。 また、JavaやEJBの基礎となっているオブジェクト指向の技術も生産性や保守性に富んだ優れた技術です。 しかし、これら2つの技術同士は実はあまり相性がよくありません。 オブジェクトと言う洗練された概念と、最も原始的である文字列を基本とするSQLとが大きくかけ離れているからです。
EJBのエンティティビーンは、これらの融合を意図したものです。 すなわちエンティティビーンはオブジェクトのままでSQL文を意識せずにDBをアクセスできるすばらしい仕組みなのです。
しかし、このようなうまい話には落とし穴があります。 それは性能です。 自動的に生成されるようなSQL文ではエンジニアが知力を尽くして書いたSQL文に対抗できる性能が出せないのです。 Sunも当初からこの点に気づいていて、2種類の手段を用意しました。 これが前述のCMPとBMPです。
CMP(コンテナ管理による永続化)では、コンテナがSQL文を生成してデータベースを自動的にアクセスし、BMP(ビーン管理による永続化)では、ビーン(プログラマー)でSQL文を記述し、コンテナはSQL文を発行するタイミングだけを判断します。 EJBの設計者は性能が問題になる場合はBMPを、そうでない場合はCMPを選ばせるつもりでした。
しかし、BMPでも性能の問題は解決しませんでした。 BMPでプログラマーが書くのは基本的なSQL文だけで、実際のアクセスはこれらを組み合わせたものになり、性能が出ないケースがあったのです。 EJB 2.0ではこの問題の改善のため専用の言語であるEJB QLを導入しましたが、あまり使われていないようです。
オブジェクト指向とリレーショナルデータベース間のこの不整合(インピーダンスミスマッチと言われる)の解決のためのさまざまな仕組みが発表されています。 この解決手段は通常はO/Rマッピング(Object Relational Mapping)と呼ばれます。 エンティティビーンもO/Rマッピングの一種ですが、フリーソフトのHibernateなどが有名です。

EJBの第三の機能はリソース管理です。 リソース管理とはできだけ少ないリソース(メモリ)で多数のクライアントからの処理を効率よくこなすための技術です。 リソース管理もEJBの重要な機能です。 同時アクセス数100が要求されるシステムで20しか対応できないとすると、CPUの増設などが必要となりコスト増の原因になります。 うまく工夫されたEJBコンテナとそうでないEJBコンテナではコストに雲泥の差が出てしまいます。
メモリを効率よく使うには色々な手法がありますが、ここではインスタンスプーリングとアクティベーションの考え方を紹介します。 どちらもクライアントがサーバと接続しても、実際にデータを処理している時間はわずかであることを利用しています。
図の上側の例ではセッションが終了するまでビーンインスタンスをメモリ上に常駐させています。 ここでビーンインスタンスとはエンタープライズビーンをメモリ上に展開したものです。 このとき、同時アクセス数は利用できるメモリ容量をビーンインスタンスのサイズで割った値(図の例では6)を超えることはできません。 しかし、下側のようにユーザがリクエストして処理が必要になった瞬間だけインスタンスを使って処理し、終わるとすぐにプールに戻す方式では多数のユーザに対してサービスできます。 この方式をインスタンスプーリングと言います。
ステートフルセッションBeanでは、クライアントアプリケーションとの関係が1対1になるのでインスタンスプーリング方式は使えません。 その場合にはアクティベーションと言うやり方で資源の節約を図っています。 それは資源が不足したとき、インスタンスをメモリから2次記憶に追い出すやり方です。 クライアントアプリケーションが再びそのインスタンスのメソッドを呼び出すと、2次記憶からメモリに復元させます。

クライアントアプリケーションがエンタープライズビーンの処理を実行するまでの手順は、以下のとおりです。
(1) クライアントアプリケーションは、ネーミングサービスでHomeオブジェクトを検索します。
(2) 検索したHomeオブジェクトのcreateメソッドを呼びます。
(3) Homeオブジェクトは、EJBオブジェクトを生成しエンタープライズビーンを初期化します。
(4) クライアントアプリケーションは、EJBオブジェクトを介してエンタープライズビーンにアクセスします。
(5) エンタープライズビーンは、EJBオブジェクトを介して処理結果を返します。
EJBを動作させるには、プログラム本体であるエンタープライズビーンの他に以下のようなプログラムが必要です。 沢山あって大変ですが、実際にはこれらを自動生成する仕組みがあって、たいていはそれが使われます。
クライアントアプリに対して公開するビジネスメソッド群のインターフェースを規定します。 リモートホームオブジェクトがEJB(リモート)オブジェクトを生成するときには、このインターフェースが実装されます。
ビーンインスタンスの生成や破棄および検索を行うためのインターフェースを定めています。 デプロイメント時にコンテナがこのインターフェースを参照してリモートホームオブジェクトを生成し、JNDIに登録します。
ビーンの種類やビーンを構成するクラス、トランザクションやセキュリティの情報などを記述します。
(注) EJB 2.0ではリモートインターフェースとホームインターフェースの代わりに、ローカルインターフェースとローカルホームインターフェースを使うことができます。 ローカルインターフェースは分散オブジェクトプロトコルのオーバーヘッドなしでビーン間通信ができるので性能面で有利です。

当初、EJBはいくつかの欲張った狙いを持っていました。 現在、それらがどの様に評価できるかを見てみましょう。
以上から、現状ではEJBの役割としてはアプリ3階層の実現のためにセッションビーン(ステートレス)を利用することのみが有効であり、その他の用途での使用は推奨できません。
最近ではEJBのような「重い」手段ではなくもっとシンプルなやり方で対応しようとするPOJO(Plain Old Java Object:普通のこれまでのJavaオブジェクト)と言う思想が出され、多くの賛同を集めています。 POJOは当初はEJB批判として言い出されたものですが、何とSun自身も考えを改め、EJB 3.0でもこの考え方を受け入れています。 このような柔軟な態度は見習いたいものです。

WebサーバとAPサーバを別マシンにすると、その間の通信のためにCORBAなどの通信手段を導入する必要があります。 CORBAは比較的容易であるとは言え、開発者はまた別の技術を習得しなければなりません。
これに対してAPサーバでEJBを採用すると、通信にはEJBのリモートオブジェクトの機能が使われCORBAを書く必要がありません。 このEJBは糊の役目を果たすだけなので、ロジックは入れずに薄く作るのがコツです。
同様な考えは、クライアントとサーバの間の結合についても言えます。 アプレットをAPサーバと結合する際にも通信手段としてCORBAが必要となります。 ここで糊としてサーブレットを採用すると、通信プロトコルはHTTPですむのでCORBAが不要となります。 この場合は業務ロジックもサーブレットで作ってしまうことも可能です。