iBatis DAO框架分析

转载自: http://blog.csdn.net/yejun8214/archive/2007/10/22/1838016.aspx 

 

为书写方便,本文采用如下简写约定:

       Transaction:Tx
       Manager:Mgr
       Context:Ctx
       Interface:Iface

 iBATIS DAO框架如图:

   iBatis DAO框架分析_第1张图片

DAO的核心在于DaoManager,DaoManager的创建代码如下:

          Reader reader = Resources.getResourceAsReader("dao.xml");
          DaoManager daoMngr = DaoManagerBuilder.buildDaoManager(reader);

DaoManager 是接口,查看 DaoManagerBuilder 源代码可发现,其 buildDaoManager 方法返回的是一个 StandardDaoManager 实例。 buildDaoManager 方法调用了XmlDaoManagerBuilder类的buildDaoManager方法,该方法完成如下工作:
1. 创建一个 StandardDaoManager 实例 stdDaoMgr
2.  创建一个用于全局收集各种 property (来自 <properties> 元素指向的资源文件或来自当前 dao.xml 中的各级 <property> 元素)的 Properties 对象
3.  解析 dao.xml 文件(建议阅读本文时参考一份dao.xml文件,如JGameStore应用中给出的dao.xml)中的 <properties> 元素,将相应 property 加入;
4.  解析 dao.xml 文件中的 <context> 元素,得到一个 DaoContext 实例 daoCtx 4.1 );并将调用 stdDaoMgr.addContext 方法将 daoCtx 添加到 stdDaoMgr 中( 4.2 ):
4.1  解析 dao.xml 文件的 <context> 元素得到 daoCtx 的过程为:
实例化一个 DaoContext 对象 daoCtx
将其 daoManager 字段设为我们的 stdDaoMgr
<context> id 属性,则将 daoCtx id 字段取为此属性的值;
解析 <context> 的子元素:
4.1.1 解析 <txMgr> 子元素,得到 DaoTxMgr 接口实例 txMgr ,设为 daoCtx 的相应字段,解析过程为:
根据 <txMgr> 子元素的 type 属性,实例化一个相应的 DaoTxMgr 实例 txMgr
解析 <txMgr> <property> 子元素,将所得 property 添加入 properties
根据 properties txMgr 进行配置(即调用 txMgr.configure 方法);
4.1.2 解析 <dao> 子元素,得到一个 DaoImpl 类实例 daoImpl ,然后将其加入 daoCtx
4.1.2 .1 解析过程为:
4.1.2 .1.1 实例化一个 DaoImpl 类实例 daoImpl
4.1.2 .1.2 daoImpl daoMgr 字段设为我们的 stdDaoMgr
4.1.2 .1.3 daoImpl daoCtx 字段设为我们的 daoCtx
4.1.2 .1.4 daoImpl daoIface 字段设为 <dao> iface 属性值对应的 class
4.1.2 .1.5 daoImpl daoImplementation 字段设为 <dao> implementation 属性值对应的 class
4.1.2 .1.6 根据 implementation 属性实例化一个 DAO 实现类,设为 daoInstance 字段值,注意,该实例一定是一个 Dao 接口实例,因为任何一个都继承自 DaoTemplate ,而 DaoTemplate 实现了 Dao 接口;
4.1.2 .1.7 创建一个当前 DAO 实现类的代理,设为 daoImpl proxy 字段值,该代理在启用显式事务时会在调用委托方法前调用 daoCtx.startTx 方法;在使用隐式事务时则在调用委托方法的前后分别调用 daoCtx.startTx 方法和 commitTx 方法(在 finally 块中还调用 daoCtx.endTx 方法)。
4.1.2 .2 daoImpl 加入 daoCtx 的过程为:以当前 daoImpl 填充一张从 daoIface DaoImpl 实例的表;
4.2  调用 stdDaoMgr.addContext 方法将 daoCtx 添加到 stdDaoMgr 中的过程为:
4.2.1 以当前 daoCtx 填充一张由 id DaoCtx 实例的表;
4.2.2遍历 daoCtx 中存放的所有 daoImpl ,填充一张从 daoIface daoCtx 的表和一张从 Dao 接口实例(即 daoImpl 中的 proxy daoInstance )到 daoCtx 的表;
5.  客户以某 DaoIface 调用 DaoMgr.getDao 方法得到一个 DaoIface 实现类实例 xxxYyyDao 的过程为:
stdDaoMgr查找其 daoIface daoCtx 的表,得到当前 daoIface 所在 daoCtx ,然后调用 daoCtx.getDao 方法:
    daoCtx 查找其从 daoIface DaoImpl 实例的表,得到 daoImpl ,返回其 proxy 字段;
6.  隐式事务:
隐式事务中,客户每调用一个 xxxYyyDao 中方法时,都是一次完整的事务,因为 xxxYyyDao 是调用 DaoMgr.getDao 方法得到的,而根据 5 ,其实 xxxYyyDao 是一个代理,又根据 4.1.2 .1.7 ,该代理会“在调用其委托方法前后分别调用 daoCtx.startTx 方法和 commitTx 方法(在 finally 块中还调用 daoCtx.endTx 方法)”。
6.1 daoCtx.startTx 方法调用其 txMgr 字段的 txMgr.startTx 方法,该方法返回一个 DaoTx 实例 daoTx daoCtx 将它放入一个线程变量中;
6.2 DaoIface 实现类中,由于其一定继承自某个 DaoTemplate ,以调用其中的数据库访问方法,而这些数据库访问方法都会以自己作为参数调用 daoMgr getTx 方法;该方法查找 4.2.2 中提到的从 Dao 接口实例到 daoCtx 的表,得到一个 daoCtx ,然后调用 daoCtx.getTx daoCtx.getTx 将存储在线程变量中的 daoTx 实例返回;
6.3 daoTx 实例包含数据库操作所需的关键元素,例如对于 SqlMapDaoTx ,其中就包含一个 SqlMapClient 实例, SqlMapDaoTemplate 中的数据库访问方法(如 insert queryForList 等)都是先调用 daoMgr.getTx ,得到 daoTx 实例,将其强制转化为 SqlMapDaoTx 实例,然后调用其 getSqlMap 方法得到 SqlMapClient 实例,再调用 SqlMapClient 实例中的相应方法;又如对于 JDBC 的情况,对应 DaoTx ConnectionDaoTx ,该类包含一个,每次调用 JdbcDaoTemplate 方法的 getConnection 方法时,该方法都先调用 daoMgr.getTx ,得到 daoTx 实例,将其强制转化为 ConnectionDaoTx 实例,然后调用其 getConnection 方法得到其中的 Connection 实例,然后调用其中的相应方法。
6.4 daoCtx.commitTx 方法调用其 txMgr 字段的 txMgr.commitTx(daoTx) 方法完成事务的提交。
6.5 daoCtx.endTx 方法调用其 txMgr 字段的 txMgr.endTx(daoTx) 方法结束事务。
7.  显式事务:
显式事务通常包括三个步骤:首先,调用 daoMgr.startTx ,然后调用 xxxYyyDao 中的方法,最后调用 daoMgr.commitTx
7.1 daoMgr.startTx 的工作非常简单,只是设置 stdDaoMgr 中标记显式事务的字段;
7.2  调用 xxxYyyDao 中的方法时,由于代理,将先调用 daoCtx.startTx ,此过程同 6.1
7.3  调用 daoMgr.commitTx 时,该方法最终调用的也是 daoCtx.commitTx ,请参考 6.4
 
下面以一个问题的实现来完成本文的总结工作:如果要由我来实现iBATIS的DAO框架对于Hibernate的支持,我们应该如何实现?
Hibernate的核心在于Session,所有的数据库操作都可调用Session上的相应方法完成,所有考虑用于支持Hibernate的DaoTx实现应该是对Session的一个包装,该实现中有一个返回当前Session的getSession方法(当然也包括提交和回滚方法)。同样的,DaoTxMgr实现类的configure方法负责完成某个Session实例(session)的配置,startTx方法负责返回一个包装了当前session实例的DaoTx实例,commitTx方法将传入的daoTx实例强制转化后调用daoTx上的commit方法,rollbackTx方法将传入的daoTx实例强制转化后调用daoTx上的rollback方法。而HibernateDaoTemplate类的关键就在于其protected的getSession方法,该方法先调用daoMgr.getTx得到当前daoTx实例,强制转化后调用daoTx上的getSession方法即可。

你可能感兴趣的:(DAO,xml,框架,Hibernate,ibatis)