IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Open source | Java technology | WebSphere  >

Geronimo への転向: Spring Framework を使って、データ・アクセスと構成の問題を軽減する

Apache Geronimo と Spring のダイナミックな組み合わせで、データ・アクセスと構成にありがちな問題を解消する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

原文はこちら

原文はこちら


レベル: 中級

Nicholas Chase (nicholas@nicholaschase.com), President, Chase and Chase, Inc.

2007年 2月 27日

典型的な開発者であれば間違いなく、データ・アクセスの問題へのソリューションを歓迎し、また構成を楽にするためのツールなら何でも喜んで採り入れるはずです。誰かにどこかの時点で Spring について説明してもらうこともなく、Web アプリケーション全般の話、そしてデータ・アクセスの問題についての具体的な話を進めることは、困難なことです。そもそも Spring 以外の Web アプリケーション・フレームワークは本当に必要なのでしょうか。私が連載「Geronimo への転向」で Apache Geronimo と Spring の共通部分を取り上げる記事を書こうと決めたのは、Spring Framework の人気の全容を突き止める潮時だとわかっていたからです。そこで私の質問攻めに遭ったのは、Jeff Genender です。

Inversion of Control による構成の簡易化

Spring Framework に関するあらゆる質問の答えを見つけるために私が頼りにしたのは、Geronimo コミッターであり、多彩な才能の持ち主でもある Jeff Genender です。Spring に馴染みのない私のような人たちのために、彼に Spring とは一体何なのかを聞いてみました。

簡単な調査で私が知ったのは、Spring は Web アプリケーションの API で、Struts には満足していない人々のためにモデル・ビュー・コントローラー (MVC) モデルの実装が組み込まれているということです。でも、どうしてそれがそれほどの一大事になるのでしょうか。そして大勢の人々をこのフレームワークに引き付けている魅力的な機能とは何なのでしょう。

「Spring は IoC コンテナーの 1 つです」。Jeff は説明を始めました。「IoC とは Inversion of Control の略で、依存関係を XML ファイルで宣言することによって依存性の注入を可能にする仕組みです」。

IoC という言葉をはじめて聞く私に Jeff が説明してくれました。彼の説明によると、アプリケーションを作成するときには通常、1 つのオブジェクトが別のオブジェクトに依存することになります。例えば、サンドイッチ・メーカーを表すビジネス・オブジェクトがあるとします。このサンドイッチ・メーカーが参照している 2 つ目のオブジェクトはサンドイッチの中身です。そのため、コードは以下のようになります (リスト 1 を参照)。


リスト 1. クラスの一例
                
package com sandwiches;

public class SandwichMaker implements FoodMaker {

    private SandwichFiller filler;
    private String currentSandwich;

    public void setSandwichFiller(SandwichFiller filler) {
        this.filler = filler;
    }

    public void setNameOfSandwich(string currentSandwich) {
        this.currentSandwich = currentSandwich;
    }

    public void makeSandwiches() {
        //make sandwiches using the SandwichFiller
    }
}

当然のことながら、実際の SandwichFiller は作ろうとしているサンドイッチの種類に依存します。つまり、ベーグル店に対する SandwichFiller クラスの実装は、サブマリン・サンドイッチ店の場合とは異なる可能性があります。SandwichMaker クラスをインスタンス化するときに該当する SandwichFiller の実装を指定するには、もちろん setSandwichFiller() メソッドを呼び出せばいいわけですが、その後、新しい場所に SandwichMaker をインストールするにはコードの変更が必要になります。Spring では、このような依存関係の定義が組み込まれたアプリケーション・コンテキストを作成できます (このため、依存性注入と呼ばれることもあります)。

アプリケーション・コンテキストのファイルはリスト2 のようになります。


リスト 2. ApplicationContext.xml ファイル
                
<beans>

  <bean id="bagel" class="com.sandwiches.BagelShop">
    <property name="breadPreference" value="bagel" />
    <property name="diameter" value="5" />
  </bean>

  <bean id="ccandjFiller" class="com.sandwiches.CreamCheeseAndJellyFiller">
    <property name="sandwichType" ref="bagel" />
    <property name="creamCheesePortion" value="60" />
    <property name="jellyPortion" value="40" />
    <property name="jellyFlavor" value="grape" />
  </bean>

  <bean id="sandwichMaker" class="com.sandwich.SandwichMaker">
    <property name="sandwichFiller" ref="ccandjFiller" />
    <property name="nameOfSandwich" value="Cream Cheese and Jelly" />
  </bean>

</beans>

それでは、このファイルを下から詳しく検討してみましょう。環境に対して指定した内容は、com.sandwich.SandwichMaker クラスをインスタンス化する際に、ccandjFiller という id の Bean を sandwichFiller プロパティーに設定するということです。この Bean は com.sandwiches.CreamCheesAndJellyFiller であり、この Bean に特有のプロパティーを持っています。そのプロパティーでは、sandwichType の bagel は、breadPreference を (ライ麦パンやビアーリではなく) bagel に設定し、幅が 5 インチです。さらに、クリーム・チーズの量をグレープ・ジャムより増やしています。

このようにさまざまなカスタマイズが行われているため、これをアプリケーションにプログラミングすると、内容が変更された場合に大量の再コンパイルが必要になります。そうでなくても、オプションを組み込んですべての項目を選べるようにする作業が大変です。Spring では、XML ファイルを変更するだけで簡単に変更を加えられるようになっています。ここではあまり苦労のない例を記載しましたが、データ・ソースを構成している場合を想像すれば、一気にこの IoC がかけがえのないものに思えてくるはずです。





上に戻る


データベースの利点

データ・ソースと言えば、Jeff の説明では、Spring はデータ・ソースに関しても優れた API を持っており、この API は多くの J2EE (および J2EE 以外の) コンポーネントを拡張するので、開発者の負担を大幅に軽減してくれるということです。

彼は説明を続けました。「Spring でデータ・アクセス・オブジェクト (DAO) を作成する作業は比較的簡単です。その方法はまず、いくつかの Spring クラスを JDBC (またはHibernate のような他のフレームワーク) で拡張し、DAO を実装してから applicationContext.xml ファイル内で宣言します。すると、この DAO のセッターを作成して Spring の XML ファイル内でビジネス・オブジェクトを宣言するだけで、そのビジネス・オブジェクトに DAO を注入できるようになります」。

IoC についての話で学んだのは以上ですが、この話は別の話題に発展しました。「この方法だと SQLExceptions をトラップする必要がなくなり、宣言を交換するのと同じくらい簡単に [データベースを] テストできるようになります」。

この最後の部分、つまり、データベースは applicationContext.xml ファイル内で簡単に設定できるプロパティーである、ということは理解できましたが、そのことによってどうして SQLExceptions をトラップする必要がなくなるのでしょうか。

「Spring は SQLExceptions を非チェック例外に変換するなどして、JDBC SQL の問題を隠蔽します。さらにエラーもクリーンアップするため、エラーの原因が何であるかが極めて明確になります。これはデータベース例外を処理するには断然優れた手法です」。

基本的には、JDBC アプリケーションの作成中に何か問題があると、SQLException を受け取ります。ですが残念ながら、この SQLException に問題を実際に突き止めるために必要なすべての情報が含まれていることは、めったにありません。実際の情報はベンダー固有のエラー・コードにエンコードされているため、それを解明しなければならないのです。もちろん、ここでは、簡単にデータ・ソースを変更できるということがポイントとしてあるため、情報をアプリケーションにコーディングするという手段は選択から除外されます。その一方、データベース操作を JdbcTemplate などの Spring クラス内にラップすれば、あらゆるエラーが確実に DataAccessException として、あるいは何よりも DataAccessException が持つ 10 前後のサブクラス (DataAccessResourceFailureException、DataIntegrityViolationException、OptimisticLockingFailureException など) のいずれかとして表現されるようになります。この方法を使えば、遥かに多くの情報を提供するようにアプリケーションをコーディングすることができます。





上に戻る


隠蔽クラスによるクラッシュの防止

Spring についてはいろいろな情報を聞くことができましたが、Geronimo に関してはどうでしょう。Spring を Geronimo アプリケーション・サーバーに統合するために、チームは何か特別な作業を行ったのでしょうか。

「確か、Bruce Snyder と Aaron Mulder が Apachecon 2006 でのプラグインに関するプレゼンテーション用に Spring プラグインを作成したと思いますが、これを除いては Spring は正真正銘の API なので、リポジトリーに配置すれば誰でも使用できます」。

つまり、チームでは特別な作業を何もする必要がなかったということです。Spring はリポジトリー内にありさえすれば、そのまま使用できるのです。

ただし、それで話が終わりというわけではありません。Jeff は説明を続けました。「他のアプリケーション・サーバーに関して人々が持っている最も大きな不満は、Spring をサーバーのクラスパスに配置しなければならないということで、Web アプリケーションにも Spring を組み込むと (アプリケーションで使用する Spring とサーバーにインストールされた Spring のバージョンが異なる場合に必要です)、現在使っている Spring がクラッシュしてしまうのです。これは、J2EE アプリケーションのクラス・ロードに関して、親から子と、子から親とで違いが出てくる部分です。

問題は、J2EE (Java™ 2 Platform, Enterprise Edition) あるいは Java EE (Java Platform, Enterprise Edition) がインスタンス化するクラスの検索を、極めて特定のレベルで開始する場合 (アプリケーションの一部となっているクラスを使用する場合) もあれば、最も一般的なレベルで開始する場合 (サーバーの一部となっているクラスを使用する場合) もあるということです。その結果、アプリケーションのコンテキストでリソースを作成することになる可能性もありますが、この場合にリソースにアクセスしようとすると、サーバーはアプリケーション・サーバーのコンテキストで検索する結果となります。

「この場合、アプリケーションは [そのアプリケーションの] Hibernate リソースを検出できなくなる等のことになります。リソースが作成された Spring コンテナーとリソースにアクセスする Spring コンテナーが異なるためです」。

当初、Geronimo 開発者たちはこの問題を解決するため、問題の原因となることが多い Spring と Apache の Commons Logging といった特定の共通クラスを自動的に隠蔽するようにしました。ですが、オープン・ソースの JSR 168 準拠ポータルである Liferay によって事態は頂点に達しました (「参考文献」でリンクを参照)。Spring を使用する Liferay は、そこにデプロイメントされているすべてのサブアプリケーションを対象とした .ear ファイルにSpring のバージョンを組み込むのです。Jeff いわく「このことについて触れた理由は、Spring を自動で隠蔽して Web アプリケーションが Spring のバージョンを EAR レベルで見られないようにしたことから、隠蔽されたクラス・ロードのアーキテクチャーによって当初の問題が発生したためです」。

ついに、Geronimo 開発者たちはソリューションを見つけ出しました。「しかし我々には、大抵のアプリケーション・サーバーより秀でたものが 1 つあります。Commons Logging 関連の問題に突き当たる人は少なくありません。例えば JBoss、Tomcat など、Commons Logging を使用するコンテナーで実行しているときに Commons Logging JAR [ファイル] をアプリケーションに組み込むと、厄介な例外が発生します」。この問題は Spring アプリケーションが最初の変更の前に遭遇した問題と同じです。「問題はまさに、クラス・ローダーのクラッシュです。Web アプリケーションが動作しないといった未解決の問題がいくつかありましたが、Tomcat や JBoss などに対して必要だったように、実は Commons Logging を削除すればいいだけの話だったのです。そこで我々は議論を重ね、Commons Logging などの妨げとなっているクラスをハードコーディングする作業に着手しました。議論はその後も続き、その結果、宣言型手法のほうが遥かに優れているという結論に達しました。このようにして、隠蔽されたクラスの宣言は誕生しました。大抵のアプリケーション・サーバーより秀でたものとは、プラン・ファイル内で隠蔽されたクラスを宣言する機能です。この機能を使用して、アプリケーションをデプロイメントするというわけです」。

「この手法は非常にうまくいっています」。Jeff は話を続けました。「そのため、他の多くのコンテナーが抱えている問題はありません。クラス・ローダーを制御して親から子、子から親への委譲を行うので、Geronimo では、アプリケーションがそれ自体に組み込まれている Spring だけを使用してサーバー・バージョンは無視すること、あるいはその逆を宣言できます。もう 1 つのプラス面は、Spring の複数のバージョンを使用できることです。サーバーでは 2.0 を使用している一方、従来のアプリケーションでは 1.x を使用していたという場合でも、クラッシュの心配は一切なく、アプリケーションが適切なバージョンを使用できます」。





上に戻る


Spring に対応した Apache Geronomo の拡張

以上の変更を行うようにチームを後押ししていたのは Spring だったかもしれませんが、これらの変更は、同じ問題が起きる可能性のあるあらゆるクラスに有効です。ただし、今後 Geronimo では Spring 固有の作業が行われないと言っているわけではありません。

私が簡単な食事を済ませている間、Jeff は 1 本の電話を終えていました。「ちょうど今、Bruce Snyder と話していたところですが、Spring の ApplicationContext を JNDI に配置できるようにするためのプラグインを作成するか拡張して、サーバー全体で Spring ベースのオブジェクトにアクセスできるようにしたいと思っています。このプラグインはクライアント用に作成したのですが、アプリケーション・サーバーでもコアの機能になるはずです。あとは作業時間が取れるかどうかの問題です」。Jeff は笑顔で言いました。

「これはどこかの時点で実現させる予定です。サーバー・ベースの Spring オブジェクトをアプリケーションに提供すれば、アプリケーションで利用したい Spring の特定のオブジェクトやオブジェクトへの参照を保管することが可能になります。例えば Quartz を使用しているときに、コンテナーへの参照が必要になったとします。オブジェクトが Spring で作成されている場合、該当するオブジェクトへの参照を持つ ApplicationContext を使う必要があるかもしれず、ApplicationContext が広範囲にわたって使用できなければなりません。ApplicationContext を JNDI に保管すれば、アプリケーションは別のコンテキストで開始された他の ApplicationContext も利用することができます。これは、サービス指向アーキテクチャーやエンタープライズ・サービス・バスをベースとしたアプリケーションにとって非常に大きな利点になるでしょうし、そのために、以前私はこの方法を生み出したのです。もっと直接的にかいつまんで言うと、共通リソースに接続されてはいないけれども、共通リソースを利用しなければならないアプリケーションに有効だということです。最適な言い方としては、SOA アプリケーションにはこの機能が必要だということです」。





上に戻る


まとめ

Geronimo コミッターとコミュニティーが行っているすべての困難な作業についてもう暫く話した後、帰る頃には何がそれほど騒がれていたのかがすっかりわかりました。Spring は手元に置いておくには非常に重宝なフレームワークだと思います。アプリケーションにあらゆる類いの構成変更が必要な場合、IoC と依存性注入がどれほど作業を楽にしてくれるかは明らかです。これまで SQLExceptions を解読しようと何時間も無駄にしてきた私は、Spring によるデータ・アクセス方法の有難さを知らないだけでした。さらに、クラス・ローダーについて、そしてあらゆる問題の解決を妨げるようなエラーが時々発生する理由について学んだ今、Geronimo の隠蔽されたクラスの宣言の有り難みを実感しています。

今度は JSF (JavaServer Faces) 技術の素晴らしいところを説明してくれる人はいないでしょうか。



参考文献

学ぶために

製品や技術を入手するために

議論するために


著者について

Nicholas Chase は、Lucent Technologies や Sun Microsystems、Oracle、the Tampa Bay Buccaneers などの会社で Web 開発に携わってきました。彼は高校の物理の先生であり、低レベル放射性廃棄物施設の管理者であり、オンライン SF 雑誌の編集者であり、マルチメディアのエンジニアであり、Oracle インストラクターであり、あるインタラクティブ・コミュニケーション会社の最高技術責任者でもあります。『XML Primer Plus』(Sams 刊) を含めて、何冊かの著作があります。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


この記事を共有する

はてなブックマーク はてなブックマーク livedoorクリップ livedoorクリップ del.icio.us del.icio.us Buzzurl(バザール) Buzzurl(バザール) Choix! Choix!
Saafブックマーク Saafブックマーク FC2ブックマーク FC2ブックマーク MM/memo MM/memo ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
CZブックマーク CZブックマーク newsing newsing




上に戻る


    日本IBMについて プライバシー お問い合わせ