Transaction Coordination using AspectJ
一度AspectJを使い出すと、アスペクト側に切り出したい処理を色々と思いつきます。GAE/Jのアプリの中でアスペクトに切り出したいと最初に思いつくのは恐らく、PersistenceManagerを取得する処理でしょう。トランザクションの部分とともに、アスペクトを用いて書いてみました。
任意のアノテーション(今回は@Transaction)が付いたメソッドが実行された(transaction()ポイントカット)ら、アスペクト側でPersistanceManagerを作ってThreadLocalにバインドしておきます(doTransaction())。以降、そのメソッド内だけでなく、そのメソッドから呼び出されている各メソッド内では、getPersistenceManager()を呼び出すことで、PersistenceManagerをThreadLocalから取り出すことができます。
@Aspect public class PersistenceManagerProvidor { private static PersistenceManagerFactory persistentManagerFactory = null; private ThreadLocal<PersistenceManager> persistenceManagerContainer = new ThreadLocal<PersistenceManager>(); @Pointcut("execution(@net.wrap_trap.bitro.annotation.Transaction * *.*(..))") public void transaction(){}; @Around("transaction()") public Object doTransaction(ProceedingJoinPoint thisJoinPoint) throws Throwable{ PersistenceManager pm = persistenceManagerContainer.get(); if(pm == null){ pm = getPersistenceManagerFromFactory(); persistenceManagerContainer.set(pm); Transaction transaction = pm.currentTransaction(); try{ transaction.begin(); Object ret = thisJoinPoint.proceed(); transaction.commit(); return ret; }finally{ if((transaction != null) && transaction.isActive()){ transaction.rollback(); } pm.close(); persistenceManagerContainer.set(null); } } return thisJoinPoint.proceed(); } @Around("cflow(transaction()) && call(* net.wrap_trap.bitro.action.Action.getPersistenceManager())") public PersistenceManager getPersistenceManager(){ return persistenceManagerContainer.get(); } protected PersistenceManager getPersistenceManagerFromFactory(){ if(persistentManagerFactory == null){ persistentManagerFactory = JDOHelper.getPersistenceManagerFactory("transactions-optional"); } return persistentManagerFactory.getPersistenceManager(); } }