技術トピックス

軽量Javaが最近もてはやされる理由

翔泳社『DBマガジン』2005年9月号「アプリケーション開発−そこが知りたい−」

石川智久/高橋英一郎/山本啓二
2005年09月01日
※内容は公開当時のものです

業務アプリなどで広く使われているJ2EE ですが、EJBはその複雑さ、難しさから敬遠されがちです。一方で、Spring やSeasar などの「DI コンテナ」や、Hibernate やiBATIS といった「O/R マッピングフレームワーク」が、実装をシンプルにする軽量Java の技術として注目を集めています。今回は、EJB の仕組みと問題点を再確認するとともに、J2EE アプリ開発における軽量Java の効果を解説します。

悩みの種は尽きません

前回の繰り返しになりますが、ソフトウェアアーキテクチャには、ソフトウェアのレイヤ構成、ユーザー認証、セッション管理、DBMSへのアクセスなど、多岐にわたる要素が含まれます。それらの中でソフトウェアのレイヤ構成は、すべてのアプリケーションに必須であるにもかかわらず、その設計と実装にこれといった一般解が存在しないため、開発者を非常に悩ませます。プレゼンテーション層、ビジネスロジック層、永続化層といった各層(レイヤ)をどのような技術を利用して実装するのか、各層の間をどう結合するのか、悩みの種は尽きることがありません。プレゼンテーション層については、最近、Struts(注1)などがデファクトスタンダード的なポジションを占めるようになり、悩むことが少なくなりました。しかし、それ以外の層に関してはなかなか単純に決めることができないのが現状です。そこで今回は、J2EE においてビジネスロジック層から永続化層までをカバーする「EJB(Enterprise JavaBean)」にスポットを当て、その仕組みと現状を見ていきます。さらに、EJB以外の選択肢となる技術を紹介します。

EJB の仕組みと問題

EJBとは

ご存知の方も多いと思いますが、EJBの概要について簡単に説明します。EJBとは、J2EE の中核をなす仕様で、一言で要約すると「サーバーサイドにおけるコンポーネント技術」です。コンポーネントという言葉もアーキテクチャに負けず劣らず実体を捉えづらい言葉ですが、ここでは「“受注処理”といった特定のサービスを提供するクラスの集合体」だと思ってください。特定の機能に特化したクラス群を一箇所に集めてコンポーネント化しておくことでクラス間の依存性を管理しやすくなり、コードの再利用性やメンテナンス性を高めることができます。大規模なシステムになるとコードの再利用性やメンテナンス性が非常に重要となってきますので、EJBはそのような状況で力を発揮してくれる技術と言えます。さらに、EJBでは各コンポーネントを分散オブジェクト(注2)として呼び出すことも可能ですので、大規模システムで問題になりがちなスケーラビリティに関しても有効です。EJBはそのほかにも、トランザクション管理、セキュリティ管理といった種々の機能を提供しています。EJBは、コンポーネントの実体である「エンタープライズBean」と、そのエンタープライズBeanが動作する環境である「EJBコンテナ」とが協力して動作します(図1)。

図1 EJBはエンタープライズBeanとEJBコンテナが協力して動作する

図1 EJBはエンタープライズBeanとEJBコンテナが協力して動作する

エンタープライズBeanは、EJBの規約に従ってコーディングされたJavaクラスで構成されます。開発したエンタープライズBeanを実行するには、EJBコンテナに「デプロイ(配置)」します。EJBコンテナは、設定に従ってエンタープライズBeanを実行可能な状態にし、エンタープライズBeanにトランザクションやセキュリティなどのさまざまなサービスを提供します。EJBコンテナがさまざまな機能を提供してくれることで、開発者はトランザクションやセキュリティなどの非機能的なコードを記述する必要がなくなり、本来の目的であるビジネスロジックの実装に注力できます。また、エンタープライズBeanには、その用途別にいくつかのタイプが存在します(図2)。

図2 さまざまなエンタープライズBean

図2 さまざまなエンタープライズBean

「エンティティBean」は、ビジネスデータを表わすコンポーネントで、DBMSとのマッピングに使用されます。「セッションBean」は、ビジネスプロセスを表わすコンポーネントで、ビジネスロジックの実行に使用されます。「メッセージ駆動型Bean」は、ビジネスプロセスを表わすコンポーネントであるという点においてはセッションBeanに似ていますが、呼び出し方法が同期ではなく非同期(呼び出した処理の終了を待たずに次の処理に移る方式)で行なわれる点がセッションBeanと大きく異なります。

複雑で難しすぎるEJB

「ソフトウェアのコンポーネント化が可能」「トランザクション管理やセキュリティ管理などをコンテナに任せられる」「分散オブジェクトも可能」と、たくさんのメリットがあるEJBです。至るところでその能力を遺憾なく発揮している……と思いきや、実情は少し異なっているようです。確かにEJBは優れた技術であり、大規模システムなど、利用される場面によっては非常に有効です。にもかかわらず、実際にEJBが利用されている場面はかなり限られており、筆者の周りでは唯一セッションBeanだけが利用されているという状況(注3)です。セッションBean以外のエンティティBeanやメッセージ駆動型Beanなどはあまり利用されません。特に、中小規模システムではこの傾向が顕著なようです。なぜでしょうか。理由は単純明快です。EJBは「複雑すぎる」のです。そもそも、EJBは多種多様な機能を提供するために非常に重厚長大な仕様となっています。現在、主に利用されているEJBのバージョン2.1の仕様書(注4)は、何と650ページを超えます。EJBが提供している機能を考えると妥当なページ数なのかもしれませんが、「ちょっと勉強しよう」というレベルからは遠くかけ離れているのは確かです。仕様の複雑さを反映するかのように、利用方法もかなり難易度が高く、一昼夜程度の付け焼刃の勉強では開発マシンを前に頭を抱えることになってしまうでしょう。実際にEJBを使用するためには、EJB固有のコーディング方法からトランザクションなどの各種設定方法、エンタープライズBeanのデプロイ方法、アプリケーションサーバー依存(!)の設定方法などさまざまなことを学習しなければなりません。その教育コストを考慮すると、多くのプロジェクトではEJBを利用することのメリットがデメリットよりも小さくなってしまうのです。ほかにもありますが、これがEJBが積極的に利用されていない主な理由です(図3)。

図3 EJB のメリットとデメリット

図3 EJB のメリットとデメリット

EJBの中でセッションBeanだけが利用されているのは、分散オブジェクトによるリモート呼び出しや、トランザクション管理の自動化といったメリットが大きいからです。ビジネスロジックをセッションBeanでラッピングしておくことで、ビジネスロジックを分散オブジェクトとしてアクセスすることが可能となります。そのため、後からシステム間連携が必要となった場合でもビジネスロジックをリモートから簡単に呼び出せますし、 スケーラビリティに関するチューニングが必要になっても比較的容易に対応できます。セッションBeanを利用していないアプリケーションにこれらの対応を行なうのは、かなりのコード変更を伴う大きな改修となってしまいます。さらに、単純なトランザクションの場合、セッションBeanを利用してEJBコンテナにトランザクション管理を任せたほうがコードがシンプルになりますし、開発の工数を抑えることができます。ただし、筆者がセッションBeanを使用する場合、複雑な設定を要する機能の利用は避け、極力設定を複雑にしないように注意しています(注5)

軽量Java の技術

ここまで述べたとおり、EJBはその複雑さ、習得の難しさからあまり積極的に利用されておらず、中小規模システムの開発では特に利用しづらい技術です。しかし、EJBをまったく使用しないと、EJBが自動化してくれていた処理まで自分で開発するハメになります。そこで、EJBより簡単に使うことのできる、EJBの代わりとして利用可能な技術が登場しました。最近では「軽量Java」などと呼ばれている技術です。軽量Javaは、EJBなどの「重量級(注6)」技術を使わずに、可能な限り簡単かつシンプルにJ2EEアプリケーションを開発するための技術です。軽量Javaでは、「DIコンテナ」や「O/Rマッピングフレームワーク」などを組み合わせることにより、J2EEアプリケーションを今までより簡単かつシンプルに開発可能にしています。

DIコンテナの仕組み

DIコンテナのDIは「DependencyInjection」の略で、日本語では「依存性注入」などと訳されます。主にクラス間の結合を緩くするために利用される技術で、DIを用いることでクラス間の結合を疎結合にすることができます。EJBの代替という視点でDIコンテナを見ると、JNDI(注7)+セッションBeanの代わりとして利用するものと言えます。代表的なDIコンテナには、SpringFramework(注8)、Seasar2(注9)、PicoContainer(注10)、HiveMind(注11)などがあります。では、DIがどういうものであるのかをサンプルコードを使って説明しましょう。

LIST1はEJBを使ったサンプルコードです。

LIST1 EJB を利用したプログラム


■OrderAction.java
public class OrderAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
OrderForm orderForm = (OrderForm)form;
InitialContext context = new InitialContext();
OrderHome home = (OrderHome) PortableRemoteObject.narrow(
initialContext.lookup("java:comp/env/ejb/OrderSessionBean"),
OrderHome.class);
OrderRemote remote = home.create();
boolean result = remote.order(orderForm.getCustomerId(),
orderForm.getItemId(),
orderForm.getQuantity());
return result ? mapping.findForward("success") : mapping.findForward("failure");
}
}
■OrderForm.java
public class OrderForm extends ValidatorForm {
private String customerId;
private String itemId;
private int quantity;
// getter、setterは略
}
■OrderRemote.java
public interface OrderRemote extends EJBObject {
boolean order(String customerId,
String itemId,
int quantity);
}
■OrderHome.java
public interface OrderHome extends EJBHome {
OrderRemote create() throws CreateException;
}
■OrderSessionBean.java
public class OrderSessionBean {
public boolean order(String customerId,
String itemId,
int quantity) {
// 注文処理を行ないます
}
}
■ejb-jar.xml
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>OrderSessionBean</ejb-name>
<home>myapp.OrderHome</home>
<remote>myapp.OrderRemote</remote>
<ejb-class>myapp.OrderSessionBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<resource-ref>
<res-ref-name>jdbc/DataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</session>
</enterprise-beans>
</ejb-jar>

Struts+EJBの開発をされている方にはお馴染みの非常に単純なコードですが、簡単に解説しておきます。まず、OrderActionクラスでJNDIを利用してOrderRemoteというセッションBeanを受け取ります。このOrderRemoteの実体はOrderSessionBeanのインスタンスです。その後、OrderActionはOrderSessionBeanのorderメソッドを実行して注文処理を行ないます。このサンプルコードのクラス図を図4に示します。

図4 LIST1 のクラス図

図4 LIST1 のクラス図

一方、LIST2のサンプルコードは、LIST1とほぼ同じ内容の処理をDIを使用して実装したものです。

LIST2 LIST1と同様の処理をDI を用いて記述したプログラム


■OrderAction.java
public class OrderAction extends Action {
private OrderLogic logic;
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
OrderForm orderForm = (OrderForm)form;
boolean result = this.logic.order(orderForm.getCustomerId(),
orderForm.getItemId(),
orderForm.getQuantity());
return result ? mapping.findForward("success") : mapping.findForward("failure");
}
public void setOrderLogic(OrderLogic logic){
this.logic = logic;
}
}
■OrderForm.java
public class OrderForm extends ValidatorForm {
private String customerId;
private String itemId;
private int quantity;
// getter、setterは略
}
■OrderLogic.java
public interface OrderLogic {
boolean order(String customerId,
String itemId,
int quantity) throws Exception;
}
■OrderLogicImpl.java
public class OrderLogicImpl implements OrderLogic {
public boolean order(String customerId,
String itemId,
int quantity) throws Exception{
// 注文処理を行ないます。
}
}

DIを使ったLIST2のほうがコードがシンプルだと思いませんか。OrderActionクラスは“なぜか”OrderLogicインスタンスをすでにprivateフィールドに保持しています。このOrderLogicの実体はOrderLogicImplクラスです。OrderActionはOrderLogicのorderメソッドを実行して注文処理を行ないます。さて、OrderActionクラスでは“なぜか”OrderLogicインスタンスが最初からセットされていると説明しましたが、OrderActionにOrderLogicImplのインスタンスをセットしているのがDIコンテナです。DIコンテナは、設定に従ってクラス間の依存関係の解決を行ないます。LIST2では、OrderActionに対してOrderLogicインターフェイスの実装を渡すことをDIコンテナにあらかじめ設定しておきます。DIコンテナはその設定に従い、OrderActionに対してOrderLogicImplを「注入」します。このサンプルコードのクラス図を図5に示します。

図5 LIST2 のクラス図

図5 LIST2 のクラス図

DIコンテナを利用することで、O r d e rActionはOrderLogicの実装(LIST2ではOrderLogicImpl)がどこに存在するのかをまったく関知せずに動作することが可能 です。ただし、これはJNDIやServiceLocator(注12)などを利用しても同じことが可能で、実際にLIST1ではJNDIを利用しています。しかし、DIを使う方法には、JNDI やServiceLocatorを使う方法と大きく異なる点が1つあります。それは、コンテナ上のオブジェクトを利用するクラス(ここではOrderAction)がDIコンテナの存在すら関知する必要がないということです。JNDI を利用しているLIST1 の場合、OrderActionはJNDIのインターフェイスをどうしても使用しなければなりません。言い換えると、OrderActionがJNDIに依存してしまっています。しかし、DIを利用しているLIST2では、OrderActionは動作に欠かすことのできないOrderLogicのインターフェイスには依存していますが、それ以外の依存関係は不要となります。これほどまでにクラス間の依存関係を気にするのは、先のEJBの解説で触れたコンポーネント化を意識しているためです。DIを利用してクラス間の依存関係を疎結合とすることで、不要な依存関係を持たない「良質な」コンポーネント化が可能となります。そして、良質なコンポーネントは再利用性やメンテナンス性を高めることに一役買ってくれます。非常に簡単な説明になりましたが、DIに関しては、今回は「クラス間を疎結合にするための技術」だという認識を持っていただければ十分です。DIに関しては、回を改めて深く解説する予定です。まとめとして、DIとEJBそれぞれの優位な点を並べてみます。

● DI が優位な点
コードがシンプル:先に比較したとおり、DIを利用するとコードが非常にシンプルになります。設定ファイルがシンプル:多くのDIコンテナでもEJBと同様に設定は専用のファイルで行なうことが多いのですが、EJB のような複数ファイルにわたる複雑な設定は必要ありません。特殊なクラス/インターフェイスに依存しない:EJB では、InitialContext、EJBHome、EJBObject などのEJB、JNDI に固有なクラス/インターフェイスの制約を受けています。しかし、DIではDIコンテナに依存するコードは一切なく、POJO(注13)として実装されています。

● EJB が優位な点
分散オブジェクトが可能:EJBでは、物理的に別のマシンからオブジェクトをリモート呼び出しすることが可能です。DIは実装によっては拡張機能などで対応可能なものも存在します。トランザクション管理の自動化:EJB ではトランザクションがEJBコンテナによって管理されています。トランザクションに関する設定はejb-jar.xml に記載されています。ただし、最近はAOP(注14)機能を搭載したDIコンテナも多く、そのようなDIコンテナではAOPを併用することでトランザクションをDIコンテナに管理させることが可能です。そのほかにもEJBコンテナが豊富な機能を提供:セキュリティ管理などもEJBコンテナが提供してくれます。EJBとDIでどちらかが絶対的に優れているということはありませんが、中小規模のシステムでは、敷居の低さや使いやすさなどの点からDIのほうが適していると言えるでしょう。

パフォーマンスも考慮されているO/R マッピングフレームワーク

O/Rマッピングフレームワークは、オブジェクトとRDBのマッピング機能を提供してくれるフレームワークです。O/Rマッピングフレームワークを利用することで、SQL文を書いたり、ResultSetから値を取り出したりといった面倒なコーディングをしなくても済みます。EJBの代替という視点からO/Rマッピングフレームワークを見ると、エンティティBeanの代わりとして使用するものと言えます。代表的なO / R マッピングフレームワークとしては、Hibernate(注15)、iBATIS(注16)などがあります。それでは、O/Rマッピングフレームワークのイメージをつかむために簡単なサンプルコードを見ていただきましょう。LIST3は、JDBCを使ってRDBにアクセスするコードです。

LIST3 JDBC を使ってDB にアクセス


public List queryCustomer() throws SQLException {
Connection con = this.getConnection(); // ① RDBMSに接続
PreparedStatement state = con.prepareStatement("select * from CUSTOMER where AGE > ?");
state.setInt(1, 20);
ResultSet rs = state.executeQuery(); // ② SQL文を発行し結果を取得
List entities = new ArrayList();
while (rs.next()) { // ③ 結果を1レコードずつオブジェクトに詰め替え
CustomerEntity customer = new CustomerEntity();
customer.setName(rs.getString("NAME"));
customer.setAddress(rs.getString("ADDRESS"));
customer.setAge(rs.getInt("AGE"));
// そのほかのフィールドを詰め替え
entities.add(customer);
}
return entities;
}

RDBMSにあるCUSTOMERテーブルに対してSELECT文を発行し、顧客リストを取得しています。具体的には、RDBMSに接続し(①)、SQL文をRDBMSへ発行して結果を受け取り(②)、結果を1レコードずつオブジェクトに詰め替える(③)という処理を行なっています。LIST4は、DBアクセスにHibernateを使っているコードです。

LIST4 O/R マッピングフレームワーク(Hibernate)を使ってDB にアクセス


public List queryCustomer() {
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
Session session = sessionFactory.openSession(); // ① Hibernateの実行準備
Query query = session.createQuery("from CUSTOMER where AGE > ?");
query.setInteger(0, 20);
return query.list(); // ② SQL文をRDBMSへ発行して結果を取得
}
■設定ファイル
<hibernate-mapping package="com.example.myapp">
<class name="CustomerEntity" table="CUSTOMER">
<id name="customerId" column="CUSTOMERID" type="string">
<generator class="assigned" />
</id>
<property name="name" type="string" column="NAME" />
<property name="address" type="string" column="ADDRESS" />
<property name="age" type="int" column="AGE" />
<!-- その他のプロパティを定義-->
</class>
</hibernate-mapping>

LIST3と同様に、CUSTOMERテーブルから顧客リストを取得しています。具体的には、Hibernate の実行準備を行ない(①)、SQL文をRDBMSへ発行して結果を受け取る(②)という処理を行なっています。LIST3と見比べると、LIST4にはSQL文の実行結果をオブジェクトにマッピングする処理がありません。Hibernateでは、RDBMSとオブジェクトのマッピング処理は設定ファイルを記述しておくことで自動的に行なわれます。これによりHibernate では、オブジェクトとRDBのマッピングを簡略化しているのです。EJB のエンティティBean には、DBMSへのアクセスを自動的に行なってくれるCMP( Container-Managed Persistence)と、DBMSへのアクセスをコーディングしなければならないBMP(Bean-Managed Persistence)の2つのモードがあります。

「楽をしようとしてCMPを利用したにもかかわらず、パフォーマンスが悪くて泣く泣くBMPに変更。頑張ってDBアクセスをコーディングしたが、後で考えてみると、エンティティBeanを利用したメリットがほとんどなかった」などという笑えない笑い話は、以前によく耳にしました。O/Rマッピングフレームワークは、CMPほど処理を自動化してくれるわけではありませんが、コーディングは楽になりますし、パフォーマンスも十分考慮されています。

また、DIコンテナにはO/Rマッピングフレームワークと連携する機能を提供しているものもあります。例えば、Seasar2ではHibernateとの連携(S2Hibernate)、SpringFrameworkではHibernateやJDO、iBATISとの連携が可能です。これらの連携機能を有効に活用することで、よりシンプルにJ2EEアプリケーションを開発することも可能です。なお、ここまでに紹介したO/Rマッピングフレームワーク機能は、実際に用意されているもののうちのごく一部です。最近では、O/Rマッピングフレームワークに関する記事や書籍が数多く出ていますので、興味のある方はそちらをご覧ください。

EJB とDI のアプリケーション構成の違い

では最後に、EJBとDIそれぞれを使ったアプリケーションの構成の違いを見てみましょう。

EJBを使ったアプリケーションの構成

EJBを使用したJ2EEアプリケーションの構成は図6のようになります。

図6 EJB を使用したJ2EE アプリケーションの構成

図6 EJB を使用したJ2EE アプリケーションの構成

Strutsなどのプレゼンテーション層のフレームワークからセッションBeanを呼び出し、セッションBeanからエンティティBeanを呼び出します。エンティティBeanはDBMSへのアクセスを行ない、その結果をセッションBean経由でプレゼンテーション層に返します。ただし、最近はエンティティBeanの代わりにO/Rマッピングフレームワークが利用されることが多く、セッションBeanからO/Rマッピングフレームワークを呼び出し、O/RマッピングフレームワークがDBMSに対してアクセスを行なうという構造が一般的となっています。

DIを使ったアプリケーションの構成

DIコンテナおよびO/Rマッピングフレームワークを使用したJ2EEアプリケーションの構成は、図7のようになります。

図7 DIコンテナ+O/Rマッピングフレームワークを使用したJ2EEアプリケーションの構成

図7 DIコンテナ+O/Rマッピングフレームワークを使用したJ2EEアプリケーションの構成

プレゼンテーション層のフレームワークが、POJOとしてコーディングされているビジネスロジッククラスを呼び出します。ビジネスロジッククラスはO/R マッピングフレームワークを呼び出し、O/RマッピングフレームワークがDBMSへのアクセスを行ないます。その際、プレゼンテーション層とビジネスロジッククラスの間の依存関係は、DIコンテナが管理します。また、一部のDIコンテナではビジネスロジッククラスとO/Rマッピングフレームワーク間の依存関係も併せて管理することが可能となっています。

おわりに

今回は、DIコンテナ+O/Rマッピングフレームワークによる軽量Javaという、流行モノを取り上げてみました。軽量Javaという言葉自体は、一過性のものであるかもしれません。しかし、アプリケーションの開発技術全体としては、「よりシンプルに、より簡単に」という方向に流れていますので、しばらくは軽量Javaのような技術から目が離せないでしょう。J2EEでは、開発を簡単にするJSF、EJB3.0といった標準技術がいくつも正式リリースを控えています。より簡単な開発環境の土台が着々と準備されつつあるのです。アプリケーション開発環境が改善されれば、無駄な作業が減り、作業の効率が上がり、そしてタクシー帰りの回数も減らせます。実は満員電車よりもタクシーのほうが楽だったりするのは周知の事実だと思いますが、やはり人間らしい時間に帰宅できるのに越したことはありません。軽量Javaなどの技術を十二分に生かして、人間らしい生活のできる開発を目指しましょう!!

コラム:Web サービスとEJB の使い分け

EJB の、特にセッションBeanの比較対象として取り上げられることの多い技術に「Webサービス」があります。Webサービスを利用すると、確かにセッションBeanと同じようにリモートからの呼び出しが可能になります。しかも、EJBによるリモート呼び出しは通常Javaオブジェクトに限定されるのに対し、Web サービスはJava に限らずさまざまな言語、さまざまなプラットフォーム間の連携に用いることができます。そのせいか、Java アプリケーションしか存在していないようなシステムでも、「いつか.Netから接続するかもしれないから」などと言ってWeb サービスを導入してしまうケースが見られます。

確かに、Webサービスのほうが汎用性は高いのですが、WebサービスにはWebサービスの、EJBにはEJB のメリット/デメリットが当然存在しますので、誤った選択をしてしまうと後で苦しむことになります。例えば、トランザクションに関してはWeb サービスよりEJB のほうが扱いがずいぶん楽ですし、パフォーマンスもEJB のほうが優れています。ですので、複雑なトランザクションを必要としたり、大量のデータ授受を必要とするような場合には、EJBを選択したほうが安全です。汎用性のみにとらわれてそのほかの要件をおろそかにしてしまわないよう心がける必要があるでしょう。

また、「EJBは後で簡単にWebサービス化できる」という思い込みで「とりあえずEJBにしておこう」という選択をしてしまうことがあります。この選択も後々の苦労につながる危険性があります。例えば、EJBでは問題なく受け渡しできているオブジェクトでも、Webサービス化すると受け渡しができなくなってしまうことがあります。Web サービスのほうが汎用性が高い分、利用できるデータ型が限られるのは仕方のないことですが、後になってこのような問題が見つかるとエンタープライズBean の外部インターフェイスを変更しなくてはならなくなり、影響範囲の広い修正が必要となってしまいます。そのため、Web サービス化をにらんだEJB 開発は、通常のEJB開発とは別のものと考えて行なうべきでしょう。

コラム:大きな期待を感じさせるEJB 3.0

現バージョンは複雑で使いづらいという評価を下されてしまったEJBですが、次バージョンのEJB 3.0では、高機能を維持しつつも複雑さを低減させるべく大幅な仕様変更が行なわれています。サン・マイクロシステムズも、J2EE の複雑さは問題視しており、EoD(Ease of Development:開発を簡単に)というスローガンを掲げ、開発の簡単化に向けたさまざまな取り組みを行なっています。EJB 3.0の仕様変更もその一環です。

本稿の執筆時点(2005 年6 月)では、EJB 3.0 のステータスは「仕様の策定中」ですが、仕様書のドラフト版「Early Draft Review 2」が公開されています(http://java.sun.com/products/ejb/docs.html)。ドラフト版を見ると、「EJB 3.0 の目的は複雑さを低減することによりアーキテクチャを改善すること」と明言されており、開発者にとっての使いやすさをかなり意識していることが分かります。また、EJB 3.0の仕様書には、その特徴について次のような記載があります。

  • 開発者の作業を減らすためアノテーション(注)を導入
  • デフォルトの設定値を規定することで、設定の手間を軽減する
  • アノテーション、DI、簡易なlookup方法を用意し、環境への依存性やJNDI アクセスを隠蔽する
  • エンタープライズBeanを単純化し、POJOやJavaBeansに近づける
  • Componentインターフェイス、HomeインターフェイスなどEJB 特有のインターフェイスの廃止
  • エンティティBean の永続化方法を単純化し、O/R マッピング用のアノテーションを導入する
  • inner join、outer join、バルクアップデート、バルクデリート、サブクエリ、group-byなどのサポート
  • 例外ハンドリングの単純化
  • コールバックインターフェイスの実装を不要にする
  • EJBコンテナ外でのテスト性を改善する

EJB 3.0では、アノテーションを導入して複雑な設定ファイルを不要とし、EJB特有のインターフェイスの廃止、DIやO/Rマッピングフレームワーク技術の導入によりコードの単純化を狙っています。これらの変更は、現行バージョンであるEJB 2.1に対する要望や批判に応えるもので、EJBが飛躍的に身近なものとなる可能性を感じさせます。

注:J2SE 5.0で新たに追加された機能で、ソースコード中に記述されるメタデータのことを表わす。

  • 注1:Apacheプロジェクトが開発を行なっているJ2EE用のWeb 層フレームワーク。http://struts.apache.org/
  • 注2:リモートのシステムから呼び出せるオブジェクトのこと。EJB のほかにも、CORBA(Common ObjectRequest Broker Architecture)やCOM+(ComponentObject Model Plus)などの仕様が有名。
  • 注3:セッションBeanにはステートレスとステートフルの2 種類が存在していますが、実際に利用されているのはほとんどがステートレスです。これは、単純にEJBでセッションを維持することがないためです。
  • 注4:EJB の仕様書は、http://java.sun.com/products/ejb/docs.htmlで入手できます。
  • 注5:それでも、結構複雑で面倒な設定が必要になってしまったりするのですが……。
  • 注6:ここで言う「重量」とは、機能が豊富な代わりに使用方法が難しくパフォーマンスもあまり良くない、という意味で使用されています。
  • 注7:ディレクトリサービスへの接続を行なうためのJava 標準インターフェイス。http://java.sun.com/products/jndi/
  • 注8:ロッド・ジョンソン氏が開発するオープンソースDIコンテナ。高機能。http://www.springframework.org/
  • 注9:ひがやすお氏らが開発する国産DIコンテナ。多数の関連プロジェクトが存在。http://www.seasar.org/
  • 注10:コードハウスで開発されているオープンソースDIコンテナ。シンプル。http://picocontainer.codehaus.org/
  • 注11:Jakarta プロジェクトによるオープンソースDIコンテナ。http://jakarta.apache.org/hivemind
  • 注12:J2EE デザインパターンの1 つで、JNDIを隠蔽するために利用される。
  • 注13:Plain Old Java Object の略で、特別なクラスやインターフェイスを継承していないオブジェクトのこと。特別なインターフェイスを必要とするEnterprise Bean との対比で良く使用される。
  • 注14:Aspect Oriented Programming の略で、日本語では「アスペクト指向プログラミング」と訳される。横断的関心事(ロギングやトランザクションなど)の分離を実現するための手法
  • 注15:ギャビン・キング氏が開発するO/R マッピングフレームワーク。http://www.hibernate.org/
  • 注16:Apache プロジェクトによるO/R マッピングフレームワーク。http://ibatis.apache.org/

石川智久(いしかわともひさ)

元々はテーブル設計が得意分野だったが、より概念的な方向に興味を持ちはじめ、アナリシスパターン的な世界へ徐々に移行中。一方で、アーキテクトとしてプロジェクトに参加する機会も増え、自分が「アーキテクト」なのか「モデラー」なのか分からなくなっている。中堅SIer を経て、2002 年より現職。

高橋英一郎(たかはしえいいちろう)

Java によるWeb アプリケーション開発一筋で生計を立てている。現職では商用J2EE Webアプリケーションフレームワークの開発に従事。いかにして楽にWebアプリケーションを構築するか、日夜頭を悩ませている。

山本啓二(やまもとけいじ)

関東在住の阪神ファン兼コンサルタント。交流戦の観戦成績は3 勝2 敗でした。阪神が好調だと、仕事にも身が入るというものです(!?)。近著「プログラマの『本懐』(日経BP 社)」

dbmagazine-writers@ulsystems.co.jp

お問い合わせ

ウルシステムズに関するお問い合わせは以下のページからどうぞ。