ibatis3出来也很久了,但一直觉得不如旧版好用,发现spring对ibatis的支持相比hibernate也简单得多,于是简单分析了下ibatis的源码。
我们知道应用程序里面使用ibatis 简单点就如下几句,
com.ibatis.sqlmap.client.SqlMapClient sqlMap = null;
java.io.Reader reader = om.ibatis.common.resources.Resources.getResourceAsReader("sql-config.xml");
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
我们从SqlMapClientBuilder.buildSqlMapClient着手,SqlMapClientBuilder中new了一个SqlMapConfigParser类来解析输入流信息,并最终实例化一个SqlMapClient返回
public static SqlMapClient buildSqlMapClient(Reader reader) {
return new SqlMapConfigParser().parse(reader);
}
1.SqlMapConfigParser类的解析
废话不多,贴代码
public class SqlMapConfigParser {
protected final NodeletParser parser = new NodeletParser();
private XmlParserState state = new XmlParserState();
private boolean usingStreams = false;
public SqlMapConfigParser() {
addSqlMapConfigNodelets();
....
}
....
public SqlMapClient parse(Reader reader) {
try {
usingStreams = false;
parser.parse(reader);
return state.getConfig().getClient();
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
.....
private void addSqlMapConfigNodelets() {
parser.addNodelet("/sqlMapConfig/end()", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().finalizeSqlMapConfig();
}
});
}
}
当调用parse时,主要执行了两步操作parser.parse(reader) 和return state.getConfig().getClient(),前者解析xml文档并将解析结果存储到
state中,后者根据解析结果生成一个SqlMapClient实例返回.那NodeletParser和XmlParserState是怎么关联起来的呢?
我们看到SqlMapConfigParser的构造函数中调用了一系列add***方法,
这些方法主要向成员变量 NodeletParser parser中添加一些回调处理类, 当NodeletParser中解析完成后调用这些回调方法将结果存储
到XmlParserState state以及state持有的config对象中.
实际上XmlParserState持有一个SqlMapConfiguration config对象,并且此config早已生成好SqlMapClientImpl对象,最后将解析结果设置进去.
SqlMapConfiguration对象生成了最主要两个类SqlMapExecutorDelegate和SqlMapClientImpl的实例.代码如下:
public class SqlMapConfiguration {
private static final Probe PROBE = ProbeFactory.getProbe();
private ErrorContext errorContext;
private SqlMapExecutorDelegate delegate;
private TypeHandlerFactory typeHandlerFactory;
private SqlMapClientImpl client;
private Integer defaultStatementTimeout;
public SqlMapConfiguration() {
errorContext = new ErrorContext();
delegate = new SqlMapExecutorDelegate();
typeHandlerFactory = delegate.getTypeHandlerFactory();
client = new SqlMapClientImpl(delegate);
registerDefaultTypeAliases();
}
....
}
2.实现类SqlMapClientImpl
SqlMapClientImpl对象一般系统只生成一个,那么此对象是怎么处理线程安全的呢?
首先我主要看一下源码中最主要的几个接口SqlMapSession,SqlMapClient,SqlMapExecutor,SqlMapTransactionManager,
UML描述如下:
SqlMapExecutor定义了CRUD等方法,SqlMapTransactionManager定义了跟事务相关的方法,SqlMapClient 接口和SqlMapSession接口都继承了SqlMapExecutor,SqlMapTransactionManager.只是SqlMapClient 增加了opensession等方法,SqlMapSession接口只增加了一个方法close().
然后看实现类SqlMapClientImpl,我们看到此类此有一个委托类SqlMapExecutorDelegate和一个ThreadLocal对象
.....
public SqlMapExecutorDelegate delegate;
protected ThreadLocal localSqlMapSession = new ThreadLocal();
public SqlMapClientImpl(SqlMapExecutorDelegate delegate) {
this.delegate = delegate;
}
public Object insert(String id, Object param) throws SQLException {
return getLocalSqlMapSession().insert(id, param);
}
......
protected SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
sqlMapSession = new SqlMapSessionImpl(this);
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
...
显然ThreadLocal是存放各个线程的session,然后看SqlMapClientImpl的insert方法,
此方法实际上调用了session实现类SqlMapSessionImpl的insert方法.那么SqlMapSessionImpl类是怎么处理的呢?
SqlMapSessionImpl实现了SqlMapSession,跟SqlMapClientImpl 有共同的实现接口SqlMapExecutor,SqlMapTransactionManager.
看源码可知此类与SqlMapClientImpl持有共同的委托对象SqlMapExecutorDelegate delegate.并且利用此委托对象实例化了一个sessionScope对象
,然后对增删改查的调用均委托对象执行处理并传入这个跟线程绑定的sessionScope对象.
public class SqlMapSessionImpl implements SqlMapSession {
protected SqlMapExecutorDelegate delegate;
protected SessionScope sessionScope;
protected boolean closed;
public SqlMapSessionImpl(SqlMapClientImpl client) {
this.delegate = client.getDelegate();
this.sessionScope = this.delegate.beginSessionScope();
...
public Object insert(String id, Object param) throws SQLException {
return delegate.insert(sessionScope, id, param);
}
SessionScope类,由源码可知此类主要保存了了执行会话一些有关的东西
public class SessionScope {
private static long nextId;
private long id;
// Used by Any
private SqlMapClient sqlMapClient;
private SqlMapExecutor sqlMapExecutor;
private SqlMapTransactionManager sqlMapTxMgr;
private int requestStackDepth;
// Used by TransactionManager
private Transaction transaction;
private TransactionState transactionState;
// Used by SqlMapExecutorDelegate.setUserProvidedTransaction()
private TransactionState savedTransactionState;
// Used by StandardSqlMapClient and GeneralStatement
private boolean inBatch;
// Used by SqlExecutor
private Object batch;
private boolean commitRequired;
private Map preparedStatements;
...
}
3.委托类SqlMapExecutorDelegate
此类持有各种根据xml解析得来的sql信息(由前面介绍的SqlMapConfigParser中的回调类置入).
还持有一个事务管理器TransactionManager txManager和一个sql执行类SqlExecutor sqlExecutor,以及一些类型工厂
代码如下:
public class SqlMapExecutorDelegate {
private static final Probe PROBE = ProbeFactory.getProbe();
private boolean lazyLoadingEnabled;
private boolean cacheModelsEnabled;
private boolean enhancementEnabled;
private boolean useColumnLabel = true;
private boolean forceMultipleResultSetSupport;
private TransactionManager txManager;
private HashMap mappedStatements;
private HashMap cacheModels;
private HashMap resultMaps;
private HashMap parameterMaps;
protected SqlExecutor sqlExecutor;
private TypeHandlerFactory typeHandlerFactory;
private DataExchangeFactory dataExchangeFactory;
....
public List queryForList(SessionScope sessionScope, String id, Object paramObject, int skip, int max) throws SQLException {
List list = null;
//根据传入的id获取具体的MappedStatement对象,每个MappedStatement对象对应xml中的一个id,存放每个执行块的具体信息传入出参数和sql执行语句
MappedStatement ms = getMappedStatement(id);
// 获得sessionScope中的事务对象
Transaction trans = getTransaction(sessionScope);
//若此事务对象为空(说明用户未显示调用session的startTransaction),这将调用sessionScope持有的事务管理器生成一个新的事务
boolean autoStart = trans == null;
try {
trans = autoStartTransaction(sessionScope, autoStart, trans);
//实例化一个StatementScope,与sessionScope对应
StatementScope statementScope = beginStatementScope(sessionScope, ms);
try {
//MappedStatement中调用sqlExecutor对statementScope执行,返回执行结果
list = ms.executeQueryForList(statementScope, trans, paramObject, skip, max);
} finally {
endStatementScope(statementScope);
}
autoCommitTransaction(sessionScope, autoStart);
} finally {
autoEndTransaction(sessionScope, autoStart);
}
return list;
}