用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中可以看到,dao的执行前后分别执行了begin和commit,这样我们就整合了AOP与IOC。
本文需要读者有一定的AOP和IOC知识。本文仅提供示例实现,提供一种思路。欢迎对此有兴趣的人来我blog探讨。
| 
   
版权声明: 
本文由冰云完成,首发于CSDN,作者保留中文版权。 
未经许可,不得使用于任何商业用途。 
欢迎转载,但请保持文章及版权声明完整。 
如需联络请发邮件:icecloud(AT)sina.com 
   |