Slim3のトランザクション管理
Slim3のトランザクション管理の部分を実装しました。
http://svn.slim3.org/browse/trunk/slim3/slim3-transaction/src/main/java/org/slim3/transaction/
一番のポイントは、どのアプリケーションサーバで動いているかを自動で検知して、適切なセットアップをすることです。これにより、単に設定が楽になるだけではなく、同じ設定ファイルで、テストのときも本番のときも動かすことができます。
設定といってもslim3_configuration.propertiesに次の一行を足すだけ。
Pluginというのは、アプリケーションの開始時と終了時に呼び出されるクラスで、通常は、Plugin#initialize()で必要な設定を行います。複数のPluginを指定する場合は、カンマで区切ります。
slim3.plugins=org.slim3.transaction.plugin.TransactionPlugin
トランザクションの機能を持たないアプリケーションサーバで動くときのロジックは次のようになります。
S3Container container = S3ContainerFactory.getInstance().getContainer(); TransactionManager tm = new TransactionManagerImpl(); UserTransaction ut = new UserTransactionImpl(tm); container.bind(UserTransaction.class.getSimpleName(), ut); TransactionController controller = new JtaTransactionController(ut, tm); container.bind(TransactionController.class.getSimpleName(), controller); TransactionSynchronizationRegistry registry = new TransactionSynchronizationRegistryImpl(tm); container.bind(TransactionSynchronizationRegistry.class.getSimpleName(), registry);
Slim3では、通常のコンポーネント(ActionとかService)は、何の設定をしなくても自動認識できます。トランザクション管理やコネクションプール管理などのインフラストラクチャ層のコンポーネントは、Pluginを使って、Javaのコードで設定します。
アプリケーションサーバを認識している部分はこんな感じ。特定のクラスが存在するかをチェックしています。
protected static boolean webSpherePresent = ClassUtil .isPresent("com.ibm.wsspi.uow.UOWManager"); protected static boolean webLogicPresent = ClassUtil .isPresent("weblogic.transaction.UserTransaction"); protected static boolean jbossPresent = ClassUtil .isPresent("org.jboss.tm.TxManager"); protected static boolean glassfishPresent = ClassUtil .isPresent("com.sun.enterprise.naming.SerialInitContextFactory"); protected static boolean geronimoPresent = ClassUtil .isPresent("org.apache.geronimo.kernel.Kernel");
JBoss、Glassfish、Geronimoを特定するクラスがこれでいいのかは、まったく自信がないので、より良いクラスがあれば教えてもらえるとうれしいです。
トランザクションをコントロールするには、UserTransactionをクラスにDIして自前で制御してもいいし、Java標準のTransactionAttributeを使うこともできます。
UserTransactionをDIするのはこんな感じ。
@Resource protected UserTransaction userTransaction;
Slim3は、名前のみでコンポーネントを探す(デフォルトはフィールド名の先頭を大文字にしたコンポーネントを探す)ので、フィールド名をuserTransactionにするか、@Resource(name = "UserTransaction")のように明示的にname属性を設定します。
TransactionAttributeの使い方はこんな感じ。
@TransactionAttribute public void foo() { ... } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void bar() { ... }
TransactionAttributeを設定しない場合は、デフォルトのREQUIREDになります。