J2EE関連の最新トピックをわかりやすく解説

J2EE Watch [7]


DIとAOPがサーバ・コンポーネント技術を変える



スティルハウス
吉川和巳
2005/6/16




DIコンテナ=軽量コンテナ?

 周知のとおり、DIコンテナとは、DI(Dependency Injection/依存性注入)の技法によりコンポーネント開発を一段と容易にするコンテナを指します。代表的なDIコンテナとしてはSpringSeasarなどが有名です。これらのDIコンテナは、EJBのような「重量級のコンテナ」によるコンポーネント開発の困難さを打開するために生み出されたもので、しばしば「軽量コンテナ」と呼ばれます。

 とはいえ最近では、EJB=重量コンテナ、DIコンテナ=軽量コンテナという単純な図式ではなくなりつつあります。例えば、標準化作業が大詰めを迎えているEJB 3.0では、DIの全面的な導入によって、EJB 2.0以前の問題点が大幅に解消される見込みです。しかし、DI化されたEJBは、果たして軽量コンテナなのでしょうか。またSeasarもEJB 3.0のEntityBean仕様への対応を表明しており、そうなるとある意味SeasarはEJBコンテナになるわけで、「アンチEJB」として登場したDIコンテナの位置付けが分かりにくくなります。

 そこで、DIが提供するメリットをより明確にするため、まず「DI」と「コンテナ」を切り離して考えてみましょう。そもそも、なぜWebアプリケーション開発で「コンテナ」が必要になるのでしょうか。

なぜコンテナが必要か

 ご存じのとおり、Webアプリケーションは、PHPやPerlなどのCGI、もしくはサーブレットやJSPのみで構築されているケースが少なくありません。では、なぜCGIやサーブレットだけでは不十分で、DIコンテナやEJBコンテナが必要な局面があるのでしょうか。その理由としては、主に以下の点が挙げられます。

  • リソース・プーリング
  • データベース・アクセス
  • トランザクション管理
  • セキュリティ管理

 Webアプリケーションのパフォーマンスやスケーラビリティ、可用性を高めるには、DBコネクションやスレッド、オブジェクトなどを多数のリクエスト間で使い回す「リソース・プーリング」が不可欠です。DIコンテナやEJBコンテナは、こうしたリソース管理機能をコンポーネントに提供します。例えばコネクション・プーリングは最も分かりやすい例です(図1)。またオブジェクトやスレッドについても、毎回作りっ放しにせずにコンテナ側できちんと管理すれば、高負荷時にもスレッド過多やメモリ不足を防ぎ、安定したサーバ運用を実現できます。

図1 コネクション・プールの例

 2つ目の理由は、Webアプリケーション構築で避けて通れない「データベース・アクセス」です。単調なJDBCプログラミングの繰り返しを防ぐには、SQLとJava間の変換やSQL生成を自動化するORM(Object/Relational Mapping)がとりわけ有用です。そこで多くのDIコンテナがHibernateに代表されるORMライブラリとの連携を実現しています。またEJBコンテナではEntityBeanがORMとして働き、DBアクセスを抑える分散キャッシュも利用できます。

 3点目は、「トランザクション管理」です。Webアプリケーションを基幹業務に利用しようとすると、単なる情報提供用のサイトとはまったく異なるレベルの信頼性が要求されます。例えば「発注処理の途中でエラーが発生して在庫テーブルのつじつまが合わなくなった」「負荷が集中するとレコードが重複してしまう」といった問題を回避するには、トランザクション管理が不可欠です。とはいえ、コードに随所にコミットやロールバックを記述したり、複数のメソッド間でDBコネクションを受け渡ししたりするのはとても面倒です。一方、DIコンテナやEJBコンテナは、JTA(Java Transaction API)ベースのトランザクション・マネージャを内蔵しており、アプリケーションに代わってトランザクションを自動制御してくれます。

 4点目は、「セキュリティ管理」です。例えば、「このリクエストはどのユーザーからのものか認証する」「このユーザーはリクエストを実行する権限を持つかチェックする」といった処理です。DIコンテナやEJBコンテナのセキュリティ機能を使えば、個々のスレッドのユーザーIDやアクセス権をコンテナ側で管理し、セキュリティ・チェックを自動化できます。

 これらのほかにも、例えばプレゼンテーション・ロジックとビジネス・ロジックを橋渡しするMVCや、JMS(Java Messaging Service)によるメッセージング、そしてRMIやXMLによるリモート呼び出しなど、DIコンテナやEJBコンテナは豊富な機能をコンポーネントに提供します

コンポーネント・モデルEJBの長所と短所

 このように、コンテナが提供する機能性そのものは、従来のEJBコンテナとDIコンテナの間に大きな違いはありません。実のところ、トランザクション・マネージャやリソース管理、セキュリティ管理、リモート呼び出しなどの機能は、メインフレームの「CICS」やUNIXサーバの「Tuxedo」といった70年代のTPモニタ製品や、「Orbix」や「VisiBroker」など90年代のCORBAベースのアプリケーション・サーバ製品の中核機能でもあります。つまり、ITシステムが基幹業務に浸透するにつれこうしたこれらの機能を必要とするのは、いまも昔も変わっていません。

 大きく変化しているのは「コンポーネント技術」です。コンポーネントの概念がなかったTPモニタやCORBAの時代、開発者は各製品のライブラリやAPIを明示的に呼び出すコードを記述していました。一方90年代に入ると、アプリケーション・サーバの分野にコンポーネントの考え方が急速に普及します。IBMのDSOM、オラクルのNCAとカートリッジ、そしてマイクロソフトDCOMなど、ベンダー各社がアプリケーション・サーバのコンポーネント・モデルを提唱しました。そして、こうした流れの集大成として、サンが1998年にEJB仕様を発表します。

 EJBは、IBMのCORBAサーバ「Component Broker」をベースとして策定された、アプリケーション・サーバのためのコンポーネント・モデルです。その最大の特徴は、さまざまな機能をコンテナがコンポーネントに「織り込む」点です。例えばEJBコンテナは、クライアントからコンポーネントへのメソッド呼び出しをインターセプト(検知)して、トランザクションの開始とコミット、セキュリティ情報のチェックと伝搬、オブジェクト内容の永続化、リソース・プーリング、リモート呼び出しなど、多様な機能を背後で実行します。そのため、コンポーネント内部でこれらのAPIを呼び出すコードを書いておく必要性が大幅に減少し、ビジネス・ロジックの記述に専念できるようになりました。

EJBの「重さ」の理由

 しかしEJBはアキレスけんを抱えていました。それは、EJBコンポーネント開発の面倒さです。EJBコンポーネントは、豊富な機能をコンテナから受け取るのと引き替えに、無数のルールや取り決めに縛られてしまったのです。

 例えば開発者は、EJBコンポーネント1つにつき以下の5つのファイルを作らなくてはなりません。

  • Enterprise Beanクラス
  • コンポーネント・インターフェイス
  • ホーム・インターフェイス
  • EJB DDファイル
  • ベンダー固有のEJB DDファイル

 Enterprise Beanクラスは、コンポーネント本体のクラスです。そしてコンポーネント・インターフェイスはコンポーネントが備えるビジネス・メソッドを定義し、ホーム・インターフェイスはコンポーネント生成のためのメソッドを定義します。さらにDDファイルは、EJBコンテナに対して「どのような機能をどの部分に織り込んでほしい」と指示するための設定用XMLファイルです。また多くの場合、ベンダー固有のDDファイルも併せて必要となります。これらのインターフェイスやクラスは、EJB仕様が定める特定のインターフェイスを実装し、特殊な命名ルールに従ってメソッドを定義しておく必要があります。さらに、EJBコンポーネントを利用するには、これらのファイルをejb-jarファイル形式にパッケージングし、EJBコンテナにデプロイ(配置)しなければなりません。

 こうした一連の作業は、EJBコンテナが「EJBオブジェクト」と呼ばれる代理オブジェクトを生成するために必要とされます。EJBコンテナは、上述のコンポーネント・インターフェイスを実装したEJBオブジェクトを動的に生成し、クライアントに渡します。このEJBオブジェクトがクライアントとEnterprise Beanの間に入り、メソッド呼び出しをインターセプトすることで、各機能の織り込みを実施する仕組みです(図2)。これはもともと、CORBAにおける分散オブジェクト間通信の実装手法(スタブ/スケルトン生成)から生まれた技法です。こうしたEJBオブジェクトのメカニズムが、EJBコンポーネントの「重さ」の大きな要因となっています。

図2 EJBオブジェクトによるインターセプト

「一枚岩」なEJB仕様

 さらに、EJBコンポーネント開発が面倒な理由の1つが、EJBがアプリケーション・サーバのすべての機能を網羅した、一枚岩の巨大仕様であることです。例えばEJBコンポーネントを利用する側のコードでは、JNDI経由でEJBコンポーネントの参照を取得したり、さまざまな例外をキャッチしたりする必要があります。以下のような具合です。

// EJBコンポーネントを呼び出すコードの例
try {
    final MySessionBeanHome msbh =
    final Context ctx = new InitialContext();
    (MySessionBeanHome) ctx.lookup("java:comp/env/ejb/mySB");
    final MySessionBean msb = msbh.create();


// ビジネス・メソッドの呼び出し
} catch (NamingException e) {
    throw new RuntimeException(e);
} catch (CreateException e) {
    throw new RuntimeException(e);
}

 上記コード例のようにわざわざJNDI経由でEJBコンポーネントを取得する理由は、ネットワークを隔てた場所のEJBコンポーネントにも透過的にアクセス可能にするためです。大半のWebアプリケーションではこのような機能は必要ありませんが、EJB仕様が一枚岩であるために、すべての機能の利用を前提としたコードを書く必要があります。

 一枚岩の仕様の弊害はほかにもあります。EJBを学ぶには、アプリケーション・サーバ全体を理解する必要があります。またEJBはアプリケーション・サーバの内部でしか動作しないため、ユニットテストも簡単には書けません。このような状況では、「単なるWebアプリケーションなのになぜこんなに面倒なの?」という疑問が生まれるのは当然といえます。

1/2

 INDEX

J2EE Watch [7]
Page1
DIコンテナ=軽量コンテナ?
なぜコンテナが必要か
コンポーネント・モデルEJBの長所と短所
EJBの「重さ」の理由
「一枚岩」なEJB仕様
  Page2
EJBオブジェクトから「DI+AOP」へ
XMLかアノテーションか
コンポーネントはDI+AOPで進化する




Java Solution全記事一覧

 



Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間