MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優秀的持久層框架。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以對配置和原生Map使用簡單的 XML 或注解,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。如何新建MyBatis源碼工程請點擊MyBatis源碼分析-IDEA新建MyBatis源碼工程。
MyBatis初始化的過程也就是創建Configuration對象的過程,下面以XML方式為例說明MyBatis是如何完成初始化的(完整測試代碼點擊MyBatis源碼分析-SQL語句執行的完整流程)。
String resouce = "conf.xml"; InputStream is = Resources.getResourceAsStream(resouce); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession session = sqlSessionFactory.openSession(); user = session.selectOne("com.luoxn28.dao.UserDao.getById", 1);
以上代碼經過了MyBatis初始化、創建SQLSession、執行SQL語句3個過程。根據conf.xml配置文件創建SqlSessionFactory對象,然后創建SqlSession對象,執行SQL語句。其中,MyBatis的初始化就發生在SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is)。
MyBatis初始化基本過程總結如下:SqlSessionFactoryBuilder根據傳入的數據流生成Configuration對象,然后根據Configuration對象創建默認的SqlSessionFactory實例。其中序列圖如下:

上圖的初始化過程經過以下的幾步:
- 1. 調用SqlSessionFactoryBuilder對象的build(inputStream)方法;
- 2. SqlSessionFactoryBuilder會根據輸入流inputStream等信息創建XMLConfigBuilder對象;
- 3. SqlSessionFactoryBuilder調用XMLConfigBuilder對象的parse()方法;
- 4. XMLConfigBuilder對象返回Configuration對象;
- 5. SqlSessionFactoryBuilder根據Configuration對象創建一個DefaultSessionFactory對象;
- 6. SqlSessionFactoryBuilder返回 DefaultSessionFactory對象給Client,供Client使用。
SqlSessionFactoryBuilder相關代碼:
public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { // 1. 創建XMLConfigBuilder對象解析XML配置 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 2. 將XML配置解析成Configuration對象,通過Configuration對象創建SqlSessionFactory return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } /** * 內部通過Configuration對象創建SqlSessionFactory,也可以通過Java API方式創建Configuration對象, * 然后調用該方法創建SqlSessionFactory */ public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
創建Configuration對象過程
接着上述的 MyBatis初始化基本過程討論,當SqlSessionFactoryBuilder執行build()方法,調用了XMLConfigBuilder的parse()方法,然后返回了Configuration對象。那么parse()方法是如何處理XML文件,生成Configuration對象的呢?
1. XMLConfigBuilder會將XML配置文件的信息轉換為Document對象,而XML配置定義文件DTD轉換成XMLMapperEntityResolver對象,然后將二者封裝到XpathParser對象中,XpathParser的作用是提供根據Xpath表達式獲取基本的DOM節點Node信息的操作。如下圖所示:


2. 之后XMLConfigBuilder調用parse()方法:會從XPathParser中取出 <configuration>節點對應的Node對象,然后解析此Node節點的子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers等。
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
解析出XML中對應的值后就設置到Configuration對象中,具體解析過程可以閱讀對應源代碼。Configuration對象創建好之后就會返回,並由此創建DefaultSqlSessionFactory對象。
mapper.xml文件是在 mapperElement(root.evalNode("mappers")); 中解析的。
參考:
1、《深入理解mybatis原理》 Mybatis初始化機制詳解
2、MyBatis源碼分析-IDEA新建MyBatis源碼工程
