DIコンテナ その2 EJB3編

http://d.hatena.ne.jp/shin/20090224/p2

の続き。

前回の機能一覧はつまらなかったのでこれから各種コンテナの実際のコードを書いてみたいと思います。サンプルコードは共通して使えるフィールドインジェクションあたりの予定です。


その第1弾はEJB3。一番コードがらくだからというのは秘密。一番設定が面倒なSeasar2は最後になる予定。

まずインターフェースを定義します。

@Local
public interface Hello{
    String getMessage(String name);
}


続いて実装コード。

@Stateless
public class HelloImpl implements Hello{
    public String getMessage(String name){
        return "はろー" + name + "さん";
    }
}


環境設定するコードや設定ファイルは必要ありません。オプションです。


実際に使用するコード。サーブレットやフィルタ、EJBJSFの管理Beanなどアプリケーションサーバーが実態を生成するものならばアノテーションによるインジェクトが可能です。JNDIによる取得は必要ありません。

@EJB
private Hello hello;

//適当に
void print(){
    System.out.println( hello.getMessage("EJB") );
}

まぁ簡単ですね。インターフェースを@Remoteに変更するとリモートインターフェースとなり、遠隔地にあるサーバーや別プロセスのアプリケーションサーバーと通信が可能です。@Localだと自分自身が所属するEJB-jarやEAR内のwarでしかアクセスが出来ないですが、シリアライズされないため高速で、その制限がありません。逆に言えばリモートだとシリアライズできないオブジェクトは使用できないということです。Streamとかはそのまま渡せないのです。



ちなみにEJB3はデフォでトランザクション管理もすべてやってくれます。例えば

@Stateless
public class HelloImpl implements Hello{
    @Resource("jdbc/sample")
    private Datasource ds;

    public String getMessage(String name){
        Connection con = ds.getConnection();
        try{
            //JDBCデータアクセスは省略
            return "はろー" + name + "さん";
        } finally{
            con.close();
        }
    }
}

こんな感じで書くとJNDIでデータソースを取得し、インジェクトしてくれます。しかも例外が発生すると自動的にロールバックされます。問題がなければこのメソッドが終わったときにコミットされます。

JPAがネイティブSQLに対してあまり力が入っていないのはおそらくデータソースインジェクトして好きにやればよいという意思の現れでしょう。JPAだろうが、データソースだろうがデータアクセスの手段はどうでも良く、それらをまとめて扱うためのJTAによるトランザクション管理だと思われます。

ちなみにJNDIのリソース注入はEJB3固有の機能ではありません。サーブレット等でも注入が可能です。ただし、トランザクション管理まではやってくれませんのでご注意を。その場合はUserTransactionをインジェクトして自分で管理すると良いでしょう。

一応EJB3の機能としては状態を保持するStatefulや非同期用MDBJPAなどもあります。JPAはJavaSEで扱うことも可能で、次期バージョンではEJBから切り離されます。なぜデータアクセスがEJB3の仕様に含まれているかといえば、元々EJB2.1までのEntityBeanがあったためでしょう。実際JPQLはEJBQLとよく似ています。


EJB3EJB 2.1までと違い、大幅に簡単に便利になっているというのが分かったでしょうか。インターフェースを用意して、それを実装するだけです。環境設定が一切いらないのも特徴でこの点は他のDIコンテナを圧倒していると思われます。

問題はJNDIを使用するときデフォルトのJNDI名が統一されていないので、面倒なJNDI定義を書いたり、実装依存になったりするところでしょうか。JavaEEの標準技術だけを使うのならばこの辺は必要になることはまずありませんけど、他のフレームワークと結合したいときに面倒になったりします。

EJB3.1ではその辺がついに改良されます。ついでにローカルインターフェースであれば@Localが省略ができるようになりました。ただのインターフェースでいいのです。ついでに言うとインターフェースですらオプションになりました。また、warと別アーカイブにする必要もありません。そして新たにシングルトンスコープが追加されます。

こうなると最も簡単なDIコンテナはEJB3.1ということになりかねないですね。期待して待ちましょう。