用PicoContainer和Nanning實現事務管理
Transaction Manager, with PicoContainer and Nanning
作者:冰雲
Blog:http://icecloud.51.net
Email:icecloud(AT)sina.com
PicoContainer是constructor injector的IOC容器。Nanning是dynamic AOP的一種實現。項目中我用Pico作爲我的微核心,在某些地方需要用到AOP,最典型的是:事務管理(Transaction Manager)。
首先考慮應用的前提,一個DAO需要進行數據庫操作並需要事務。下面是兩個接口聲明:
public interface Dao { void update(); Object create(); }
public interface TxManager { void begin(); void commit(); void rollback(); }
|
如果用OO的實現方法,可能是要讓SampleDao這個實現類同時實現兩個接口等。按照單一職責原則,SampleDao不應該瞭解事務管理,或者,某種情況下,不需要事務處理,這時候應該可以關閉事務。
這裏引入Aspect(方面)來負責事務處理。或者說,事務其實是Service的一個方面。
但是,一個問題是,事務往往和數據庫相關。想要控制事務,必須要能夠啓動事務的Connection,Session,Transaction等等。必須把這些東西同時傳遞給Service和TxManager。
public interface ObjectReference{ Object get(); void set(Object obj); }
public class DatabaseReference implements ObjectReference{ private Connection conn ;
public DatabaseReference(){ // 從某處取得Connection } Objcet get(){ return conn; } void set(Object obj){ this.conn = (Connection)obj; } }
|
TxManager的實現類可以擁有一個 DatabaseReference的實例用來獲取和Connection相關的對象。Service的實例也要得到同一個DatabaseReference,這樣TxManager控制同一個Connection的事務纔有效果。
示例如下,系統中我是使用的Hibernate的Session
public class TxManagerImpl implements TxManager { private Connection conn; public TxManagerImpl(DatabaseReference dref) { this.conn = (Connection)dref; } public void begin() { conn.setAutoCommit(false); } public void commit() { conn.commit(); } public void rollback() { conn.rollback(); } }
public class SampleDao implements Dao { Connection conn; public SampleDao(DatabaseReference dref){ this.conn = (Connection)dref.get(); } void update() { conn.executeQuery("..."); } }
|
Dao和TxManager之間有了紐帶:DatabaseReference。然而,如果要控制事務,還需要一個控制類,將所有的Dao操作置於事務管理內。
public class TransactionAspect implements Aspect { Pointcut transactionPointcut = P.all(); TxManager txManager;
public TransactionAspect(TxManager transactionManager) { this.txManager = transactionManager; }
public void introduce(AspectInstance arg0) { }
public void advise(AspectInstance instance) { transactionPointcut.advise(instance, new MethodInterceptor() { public Object invoke(Invocation invocation) throws Throwable { txManager.begin(); try { Object o = invocation.invokeNext(); txManager.commit(); return o; } catch (Exception e) { txManager.rollback(); throw e; } } }); } }
|
這時就可以建立一個調用的實例了,這就需要PicoContainer來負責對象的創建和管理:
MutablePicoContainer pico = new DefaultPicoContainer( new CachingComponentAdapterFactory( new NanningComponentAdapterFactory()));
pico.registerComponentImplementation(TxManager.class, TxManagerImpl.class); pico.registerComponentImplementation(TransactionAspect.class, TransactionAspect.class); pico.registerComponentImplementation(SampleDao.class);
pico.getComponentInstances();
Dao dao = (Dao) pico.getComponentInstance(SampleDao.class); dao.update();
|
上面用到的NanningComponentAdapterFactory,是NanoContainer中nanning包提供,負責將Nanning實例整合到PicoContainer。
從log中可