CDIで複数データソースの切り替え

将来的にはJavaEEの仕様にマルチテナント機能が組み込まれますが、
僕は今のところ、複数データソースの切り替えが出来れば十分なので、
CDIを使ってやってみました。
これで1つのJavaEE6アプリで複数のデータベースへの接続を切り替える事が可能です。

では早速、実際のソースを見てみましょう。

 

まずはプロデューサ・メソッドから。
EntityManagerがDIされるフィードを複数持ち、プロデューサ・メソッドで何れかをreturnします。
今回の例ではシステム日付の秒で分岐しましたが、
実際はURLパラメータやCookieに保持した値などで分岐する事になると思います。
また、RequestScopedアノテーションを付けて、リクエスト毎に呼ばれるようにします。 {% codeblock lang:java %} public class EntityManagerFactory {

@PersistenceContext(unitName = "pu01")
private EntityManager em01;
@PersistenceContext(unitName = "pu02")
private EntityManager em02;

@RequestScoped
@Produces
@EntityManagerQualifier
public EntityManager getEntityManager() {
    // システム日付が偶数秒ならem01に接続する。
    DateTime dt = new DateTime();
    int sec = Integer.parseInt(dt.toString("s"));
    if (sec % 2 == 0) {
        return em01;
    } else {
        return em02;
    }
}

} {% endcodeblock %}

次にDIでEntityManagerを受け取る側
DIで受け取ったEntityManagerを使うだけです。
今回の例ではコントローラに書いてます。 {% codeblock lang:java %} @Model public class SampleController {

@Inject
@EntityManagerQualifier
private EntityManager em;

public String getName() {
    Query query = em.createNamedQuery("findAll", Sample.class);
    return ((Sample) query.getSingleResult()).getName();
}

} {% endcodeblock %}

EntityManagerQualifierアノテーションはQualifier(限定子)です。
インジェクションの対象を限定(紐付け?)させています。 {% codeblock lang:java %} @Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface EntityManagerQualifier { } {% endcodeblock %}

ソースはGitHubにアップしてます。
READMEに環境構築の手順メモも書いてます。
サンプルソース

以上、久々のJavaネタでした!

 
comments powered by Disqus