免費(fèi)微網(wǎng)站建站系統(tǒng)百度官方認(rèn)證
初始化基本過(guò)程(引導(dǎo)層部分)
文章目錄
- 初始化基本過(guò)程(引導(dǎo)層部分)
- 一:初始化的方式及引入
- 二:初始化方式-XML配置文件
- 1:MyBatis初始化基本過(guò)程
- 2:創(chuàng)建Configuration對(duì)象的過(guò)程
- 2.1:將XML的信息轉(zhuǎn)換為Document對(duì)象
- 2.2:調(diào)用parse()方法
- 2.3:設(shè)置到Configuration對(duì)象中
- 三:初始化方式-基于Java API
MyBatis和數(shù)據(jù)庫(kù)的交互有兩種方式有Java API和Mapper接口兩種,所以MyBatis的初始化必然也有兩種;
那么MyBatis是如何初始化的呢?
一:初始化的方式及引入
MyBatis的初始化可以有兩種方式:
- 基于XML配置文件 -> 基于XML配置文件的方式是將MyBatis的所有配置信息放在XML文件中,MyBatis通過(guò)加載并XML配置文件,將配置文信息組裝成內(nèi)部的Configuration對(duì)象
- 基于Java API -> 這種方式不使用XML配置文件,需要MyBatis使用者在Java代碼中,手動(dòng)創(chuàng)建Configuration對(duì)象,然后將配置參數(shù)set 進(jìn)入Configuration對(duì)象中
二:初始化方式-XML配置文件
現(xiàn)在就從使用MyBatis的簡(jiǎn)單例子入手,深入分析一下MyBatis是怎樣完成初始化的,都初始化了什么。
// mybatis初始化
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource); // 資源 -> inputStream
// 直接
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通過(guò)build配置構(gòu)建SqlSession工廠// 通過(guò)工廠創(chuàng)建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();// 執(zhí)行SQL語(yǔ)句
List<Blog> list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo")
上述語(yǔ)句的作用是執(zhí)行com.foo.bean.BlogMapper.queryAllBlogInfo
定義的SQL語(yǔ)句,返回一個(gè)List結(jié)果集。
總的來(lái)說(shuō),上述代碼經(jīng)歷了三個(gè)階段:mybatis初始化 -> 創(chuàng)建SqlSession -> 執(zhí)行SQL語(yǔ)句
上述代碼的功能是根據(jù)配置文件mybatis-config.xml 配置文件,創(chuàng)建SqlSessionFactory對(duì)象,然后產(chǎn)生SqlSession,執(zhí)行SQL語(yǔ)句
而mybatis的初始化就發(fā)生在第三句:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1:MyBatis初始化基本過(guò)程
SqlSessionFactoryBuilder根據(jù)傳入的數(shù)據(jù)流生成Configuration對(duì)象,然后根據(jù)Configuration對(duì)象創(chuàng)建默認(rèn)的SqlSessionFactory實(shí)例
初始化的基本過(guò)程如下序列圖所示:
- 調(diào)用
SqlSessionFactoryBuilder#build(inputStream)
方法; - SqlSessionFactoryBuilder會(huì)根據(jù)輸入流inputStream等信息創(chuàng)建XMLConfigBuilder對(duì)象;
- SqlSessionFactoryBuilder調(diào)用
XMLConfigBuilder#parse()
方法; - XMLConfigBuilder對(duì)象返回Configuration對(duì)象;
- SqlSessionFactoryBuilder根據(jù)Configuration對(duì)象創(chuàng)建一個(gè)DefaultSessionFactory對(duì)象;
- SqlSessionFactoryBuilder返回DefaultSessionFactory對(duì)象給Client,供Client使用。
SqlSessionFactoryBuilder相關(guān)的代碼如下所示:
// 1:SqlSessionFactoryBuilder#build(inputStream)的入口方法,可以看見是調(diào)用多參數(shù)的build方法
public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null);
} // 多參數(shù)build,在這里返回最后的SqlSessionFactory
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //2. 創(chuàng)建XMLConfigBuilder對(duì)象用來(lái)解析XML配置文件,生成Configuration對(duì)象 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //3. 將XML配置文件內(nèi)的信息解析成Java對(duì)象Configuration對(duì)象 Configuration config = parser.parse(); //4. 根據(jù)Configuration對(duì)象創(chuàng)建出SqlSessionFactory對(duì)象 return build(config); } 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. } }
}// 從此處可以看出,MyBatis內(nèi)部通過(guò)Configuration對(duì)象來(lái)創(chuàng)建SqlSessionFactory
// 5:用戶也可以自己通過(guò)API構(gòu)造好Configuration對(duì)象,調(diào)用此方法創(chuàng)SqlSessionFactory
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config);
}
上述的初始化過(guò)程中,涉及到了以下幾個(gè)對(duì)象:
對(duì)象 | 說(shuō)明 |
---|---|
SqlSessionFactoryBuilder | SqlSessionFactory的構(gòu)造器,用于創(chuàng)建SqlSessionFactory,采用了Builder設(shè)計(jì)模式 |
SqlSessionFactory | SqlSession工廠類,以工廠形式創(chuàng)建SqlSession對(duì)象,采用了Factory工廠設(shè)計(jì)模式 |
Configuration | 該對(duì)象是mybatis-config.xml文件中所有mybatis配置信息 |
XmlConfigParser | 負(fù)責(zé)將mybatis-config.xml配置文件解析成Configuration對(duì)象 |
2:創(chuàng)建Configuration對(duì)象的過(guò)程
XmlConfigParser是如何通過(guò)
parse()
方法將mybatis-config.xml配置文件解析成Configuration對(duì)象的?
2.1:將XML的信息轉(zhuǎn)換為Document對(duì)象
而XML配置定義文件DTD轉(zhuǎn)換成XMLMapperEntityResolver對(duì)象,然后將二者封裝到XpathParser對(duì)象中
XpathParser的作用是提供根據(jù)Xpath表達(dá)式獲取基本的DOM節(jié)點(diǎn)Node信息的操作
2.2:調(diào)用parse()方法
會(huì)從XPathParser中取出<configuration>
節(jié)點(diǎn)對(duì)應(yīng)的Node對(duì)象,然后解析此Node節(jié)點(diǎn)的子Node
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 源碼中沒(méi)有這一句,只有 parseConfiguration(parser.evalNode("/configuration")); // 下面是將源碼拆分為以下兩句 XNode configurationNode = parser.evalNode("/configuration"); parseConfiguration(configurationNode); return configuration;
}
/** * 解析 "/configuration"節(jié)點(diǎn)下的子節(jié)點(diǎn)信息,然后將解析的結(jié)果設(shè)置到Configuration對(duì)象中 */
private void parseConfiguration(XNode root) { try { //1.首先處理properties 節(jié)點(diǎn) propertiesElement(root.evalNode("properties")); //issue #117 read properties first //2.處理typeAliases typeAliasesElement(root.evalNode("typeAliases")); //3.處理插件 pluginElement(root.evalNode("plugins")); //4.處理objectFactory objectFactoryElement(root.evalNode("objectFactory")); //5.objectWrapperFactory objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); //6.settings settingsElement(root.evalNode("settings")); //7.處理environments environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 //8.database databaseIdProviderElement(root.evalNode("databaseIdProvider")); //9.typeHandlers typeHandlerElement(root.evalNode("typeHandlers")); //10.mappers mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); }
}
在上述代碼中,還有一個(gè)非常重要的地方,就是解析XML配置文件子節(jié)點(diǎn)<mappers>
的方法mapperElements(root.evalNode("mappers"))
它將解析我們配置的Mapper.xml配置文件,Mapper配置文件可以說(shuō)是MyBatis的核心
MyBatis的特性和理念都體現(xiàn)在此Mapper的配置和設(shè)計(jì)上
2.3:設(shè)置到Configuration對(duì)象中
各個(gè)過(guò)程就不深究了,這里就看上述的environmentsElement(root.evalNode("environments"))
方法
探究一下這個(gè)方法是如何將environments的信息解析出來(lái),設(shè)置到Configuration對(duì)象中的
/** * 解析environments節(jié)點(diǎn),并將結(jié)果設(shè)置到Configuration對(duì)象中 * 注意:創(chuàng)建envronment時(shí),如果SqlSessionFactoryBuilder指定了特定的環(huán)境(即數(shù)據(jù)源); * 則返回指定環(huán)境(數(shù)據(jù)源)的Environment對(duì)象,否則返回默認(rèn)的Environment對(duì)象; * 這種方式實(shí)現(xiàn)了MyBatis可以連接多數(shù)據(jù)源 */
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { // 如果沒(méi)有指定特定的環(huán)境,就用默認(rèn)的環(huán)境配置defaultenvironment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { // 只有environment.equals(id)情況會(huì)進(jìn)入//1.創(chuàng)建事務(wù)工廠 TransactionFactory TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); //2.創(chuàng)建數(shù)據(jù)源DataSource DataSource dataSource = dsFactory.getDataSource(); //3.構(gòu)造Environment對(duì)象 Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); //4.將創(chuàng)建的Envronment對(duì)象設(shè)置到configuration 對(duì)象中 configuration.setEnvironment(environmentBuilder.build()); } } }
}// 各種特殊環(huán)境的判斷
private boolean isSpecifiedEnvironment(String id) { if (environment == null) { throw new BuilderException("No environment specified."); } else if (id == null) { throw new BuilderException("Environment requires an id attribute."); } else if (environment.equals(id)) { return true; } return false;
}
最后返回Configuration對(duì)象就可以了
三:初始化方式-基于Java API
當(dāng)然我們可以使用XMLConfigBuilder手動(dòng)解析XML配置文件來(lái)創(chuàng)建Configuration對(duì)象,代碼如下:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource); // resource -> inputstream // 手動(dòng)創(chuàng)建XMLConfigBuilder,并解析創(chuàng)建Configuration對(duì)象,就是上面分析的源碼,主動(dòng)調(diào)用
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); // 看這里
Configuration configuration = parser.parse(); // 使用Configuration對(duì)象創(chuàng)建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); // 使用MyBatis factory工廠模式先創(chuàng)建SqlSession,然后有了門面API,就可以操作了
SqlSession sqlSession = sqlSessionFactory.openSession();
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");