リモート処理
メッセージングが一般的にシステム間での非同期メッセージの交換を伴うのに対し、リモート処理はシステム間での同期の要求を出す機能です。リモート処理は、例えばこのシリーズで扱っているフライト予約のアプリケーションにおいて乗客のクレジットカード認証を行う場合など、さまざまなケースで役立ちます。今日最もよく知られているリモート処理の仕組みは、WebサービスとRMI(リモートメソッド呼び出し)です。一般にWebサービスの要求はHTTPを介して送信されるため、企業のファイアウォールを通してルーティングできます。Webサービスのメッセージ構造はXMLであるため、特定のプラットフォームやプログラミング言語には依存していません。これに対し、RMIは一般にJavaアプリケーション間の通信に用いられ、通常はファイアウォールを通してのルーティングはできません。
リモート処理 - 機能の比較
リモート処理の比較にあたり、航空券の購入処理を進める予約エージェントの役割を考えてみましょう(図2を参照)。
このユースケースのためのテストは、第1回の記事にコードリストを掲載済みです。テストの基準は、Springでリモート予約エージェントを実装すれば満たすことができます。この実装では、リモートアクセスを可能にするためにSpringの予約エージェントに対して行うべきことは何もありません。必要なのは、次に示すように、RmiServiceExporter
を使ってこの予約エージェントをエクスポートすることだけです。
<bean class="org.springframework.remoting.rmi.RmiServiceExporter" lazy-init="false"> <property name="serviceName" value="bookingAgentService" /> <property name="service" ref="remoteBookingAgentService" /> <property name="serviceInterface" value="org.jug.flight.booking.BookingAgent" /> <property name="registryPort" value="1199" /> </bean> <bean id="remoteBookingAgent" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <property name="serviceUrl" value="rmi://localhost:1199/bookingAgentService" /> <property name="serviceInterface" value="org.jug.flight.booking.BookingAgent" /> </bean>
EJB 3.0バージョンの予約エージェントをリモート化する場合も、次に示すように、このエージェントにリモートコンポーネントとしての注釈を付けるだけで済みます。
@Stateful @Remote public class BookingAgentEJB implements BookingAgent { ... }
どちらの場合も、リモート呼び出し側に予約エージェントを公開するためにエージェントのインターフェイスやロジックを変更する必要がないことに注意してください。事実、Springによる実装では予約エージェントに対する変更は一切必要ありませんでした。EJB 3.0でも、上記のような注釈ではなくXMLを用いてこのコンポーネントをリモートとして宣言すれば、実装の変更は不要になります。
リモート処理 - 機能以外の比較
EJBによるリモート処理はRMIの上に構築されており、セキュリティ伝播やトランザクション伝播のサポートによって分散Javaアプリケーションの開発を容易にします。またステートレスEJBも、JSR181(Javaプラットフォーム向けのWebサービスのメタデータ)で定義されているメタデータの注釈を使えばWebサービスとして公開できます。
Spring 2.0は、RMIやWebサービスの他に、Hessian、Burlap、HTTP Invoker(JDKのシリアライズを使用)など、さまざまな形のリモート処理をサポートしています。またEJBと異なるのが、任意のPOJOをリモートオブジェクトとして公開できる点です。これはSpringのヘルパークラスの組み合わせと設定によって実現されます。しかし、Springのリモート処理は、EJBがサポートしているセキュリティおよびトランザクションの伝播をサポートしていません。
リモート処理 - まとめ
表2に、リモート処理のサポートについてのSpringとEJB 3.0の違いをまとめておきます。
機能 | Spring | EJB 3.0 |
サポートされるプロトコル | RMI、Webサービス、Hessian、Burlap、HTTP | RMI、Webサービス |
リモートオブジェクトの公開 | √(任意のPOJO) | √(EJBのみ) |
インスタンスプールおよびロードバランシング | -- | √ |
トランザクション伝播 | -- | √ |
セキュリティ伝播 | -- | √ |
依存性管理
依存性管理とは、システム内のコンポーネント間のやり取りを制御する機能です。こうした相互依存性の具現化(ワイヤリング)によって、開発者はより緩やかに結合されたシステムを作成しようとします。一般に結合度の低いシステムは、拡張、テスト、メンテナンスが容易です。また、依存性管理の具現化は制御の反転(IoC:Inversion of Control)とも呼ばれ、クラスに依存性を注入する動作は依存性注入(dependency injection)と呼ばれます。
依存性注入の基本的な形として、セッター(設定メソッド)、コンストラクタ、およびフィールドの3種類の注入(インジェクション)があります。セッターインジェクションとコンストラクタインジェクションの解説については、Martin Fowlerの記事『Inversion of Control Containers and the Dependency Injection Pattern』を参照してください。ただし、フィールドインジェクションの有用性については議論の余地があります。フィールドインジェクションはJEEの依存性注入の注釈を用いるときには確かに便利ですが、カプセル化の原則に反しているため、クラスの単体テストが難しくなるのです。
SpringとEJB 3.0はどちらも依存性管理をサポートしていますが、実装する依存性注入の種類が異なります。Springはセッターベースおよびコンストラクタベースの両方の注入をサポートしています。一方のEJB 3.0はセッターインジェクションとフィールドインジェクションをサポートしています。どちらにも制約があるわけですが、SpringやEJB 3.0による依存性管理のサポートを検討する際には、このわずかな違いに注意する必要があります。
Springフレームワークのコア機能の1つがIoCフレームワークなので、成熟度と設定の容易さでEJB 3.0を上回る依存性管理の機能をSpringがサポートしているのは当然と言えます。通常、Springの依存関係はXML設定ファイルを介してマッピング(または「ワイヤリング」)されます。一方、JEE 5(厳密に言うとEJB 3.0)でコードを書く初歩的な方法は、ソースコード注釈を用いるものです。注釈には修飾対象のコードのより近くに位置するという利点があるため、システムの理解性を向上させることができます。その反面、コンパイル時および実行時の依存関係が生じるため、注釈を付けたクラスの移植性は低下します。
Springでは、次のようにXMLを用いてアプリケーションの依存関係を設定するのが最も一般的です。
<bean id="bookingAgentSpring" class="org.jug.flight.booking.spring.BookingAgentSpring"> <property name="flightDAO" ref="flightDAO" /> <property name="ticketDAO" ref="ticketDAO" /> </bean>
これに対し、JEE 5やEJB 3.0では多くの場合、注釈の形で依存性注入が行われます。
@Stateful @Remote public class BookingAgentEJB extends AbstractStatefulBookingAgent implements BookingAgent { @EJB private FlightDAO flightDAO; @EJB private TicketDAO ticketDAO; ... }
相互依存性が高く、リソース要求が厳しい大規模なアプリケーションでは、ワイヤリングが非常に厄介な作業になることがあります。依存関係を暗黙的にワイヤリングする依存性注入コンテナの機能は、オートワイヤリングと呼ばれます。SpringとEJB 3.0はどちらも、名前と型の両方によって依存関係のワイヤリングを行うことができます。
Spring独自の機能としては、オブジェクトのインスタンスを作成するためにファクトリBeanを呼び出せるものがあります。この機能を使えば、注入のためのオブジェクトインスタンスを作成するためにオブジェクトファクトリを呼び出すことが可能です。そのため開発者は、オブジェクトの作成をプログラム的に制御できるほか、レガシーコードをSpringの依存性管理の仕組みに適応させることもできます。
Springフレームワークにおける依存性管理の威力は、任意のオブジェクトの管理やレガシーコードベースとの統合が可能なことと、高度な拡張性および設定容易性にあります。EJB 3.0の依存性管理の機能は便利ですが、Springほど堅牢なものではありません。表3に、依存性管理のサポートに関するSpringとEJB 3.0の違いをまとめておきます。
機能 | Spring | EJB 3.0 |
セッターインジェクション | √ | √ |
コンストラクタインジェクション | √ | -- |
フィールドインジェクション | -- | √ |
オートワイヤリング | √(名前および型による) | √(名前および型による) |
ファクトリBean | √ | -- |
ファクトリメソッド | √ | -- |
JNDIインジェクション | √ | √ |
設定 | 主としてXML | 主として注釈 |
スコープ | 任意のオブジェクト | JEEの特定の型 |