本文共享自华为云社区《MyBatis详解 – 初始化根本进程》,作者:龙哥手记 。
MyBatis初始化的办法及引入
MyBatis的初始化能够有两种办法:
-
依据XML装备文件:依据XML装备文件的办法是将MyBatis的一切装备信息放在XML文件中,MyBatis经过加载并XML装备文件,将装备文信息组装成内部的Configuration目标。
-
依据Java API:这种办法不运用XML装备文件,需要MyBatis运用者在Java代码中,手动创立Configuration目标,然后将装备参数set 进入Configuration目标中。
初始化办法 – XML装备
接下来咱们将经过 依据XML装备文件办法的MyBatis初始化,深入探讨MyBatis是怎么经过装备文件构建Configuration目标,并运用它。
现在就从运用MyBatis的简略比如下手,深入分析一下MyBatis是怎样完结初始化的,都初始化了什么。看以下代码:
// mybatis初始化
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 创立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 履行SQL句子
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");
有过MyBatis运用经验的读者会知道,上述句子的作用是履行com.foo.bean.BlogMapper.queryAllBlogInfo
界说的SQL句子,回来一个List成果集。总的来说,上述代码经历了三个阶段(本系列也对应三篇文章别离解说):
-
mybatis初始化
本文 -
创立SqlSession
– 详解后文 -
履行SQL句子
– 详解后文
上述代码的功用是依据装备文件mybatis-config.xml 装备文件,创立SqlSessionFactory目标,然后发生SqlSession,履行SQL句子。而mybatis的初始化就发生在第三句:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 现在就让咱们看看第三句究竟发生了什么。
MyBatis初始化根本进程:
SqlSessionFactoryBuilder依据传入的数据流生成Configuration目标,然后依据Configuration目标创立默认的SqlSessionFactory实例。
初始化的根本进程如下序列图所示:
由上图所示,mybatis初始化要经过简略的以下几步:
-
调用SqlSessionFactoryBuilder目标的build(inputStream)办法;
-
SqlSessionFactoryBuilder会依据输入流inputStream等信息创立XMLConfigBuilder目标;
-
SqlSessionFactoryBuilder调用XMLConfigBuilder目标的parse()办法;
-
XMLConfigBuilder目标回来Configuration目标;
-
SqlSessionFactoryBuilder依据Configuration目标创立一个DefaultSessionFactory目标;
-
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 {
//2. 创立XMLConfigBuilder目标用来解析XML装备文件,生成Configuration目标
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//3. 将XML装备文件内的信息解析成Java目标Configuration目标
Configuration config = parser.parse();
//4. 依据Configuration目标创立出SqlSessionFactory目标
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内部经过Configuration目标来创立SqlSessionFactory,用户也能够自己经过API结构好Configuration目标,调用此办法创SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
上述的初始化进程中,涉及到了以下几个目标:
-
SqlSessionFactoryBuilder : SqlSessionFactory的结构器,用于创立SqlSessionFactory,采用了Builder规划模式
-
Configuration :该目标是mybatis-config.xml文件中一切mybatis装备信息
-
SqlSessionFactory:SqlSession工厂类,以工厂方法创立SqlSession目标,采用了Factory工厂规划模式
-
XmlConfigParser :负责将mybatis-config.xml装备文件解析成Configuration目标,共SqlSessonFactoryBuilder运用,创立SqlSessionFactory
创立Configuration目标的进程
接着上述的 MyBatis初始化根本进程评论,当SqlSessionFactoryBuilder履行build()办法,调用了XMLConfigBuilder的parse()办法,然后回来了Configuration目标。那么parse()办法是怎么处理XML文件,生成Configuration目标的呢?
- XMLConfigBuilder会将XML装备文件的信息转换为Document目标
而XML装备界说文件DTD转换成XMLMapperEntityResolver目标,然后将二者封装到XpathParser目标中,XpathParser的作用是供给依据Xpath表达式获取根本的DOM节点Node信息的操作。如下图所示:
- 之后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"));
//为了让读者看得更明晰,源码拆分为以下两句
XNode configurationNode = parser.evalNode("/configuration");
parseConfiguration(configurationNode);
return configuration;
}
/**
* 解析 "/configuration"节点下的子节点信息,然后将解析的成果设置到Configuration目标中
*/
private void parseConfiguration(XNode root) {
try {
//1.首先处理properties 节点
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);
}
}
注意:在上述代码中,还有一个非常重要的当地,便是解析XML装备文件子节点<mappers>
的办法mapperElements(root.evalNode(“mappers”)), 它将解析咱们装备的Mapper.xml装备文件,Mapper装备文件能够说是MyBatis的核心,MyBatis的特性和理念都表现在此Mapper的装备和规划上。
- 然后将这些值解析出来设置到Configuration目标中
解析子节点的进程这儿就不一一介绍了,用户能够参照MyBatis源码仔细揣摩,咱们就看上述的environmentsElement(root.evalNode(“environments”)); 办法是怎么将environments的信息解析出来,设置到Configuration目标中的:
/**
* 解析environments节点,并将成果设置到Configuration目标中
* 注意:创立envronment时,假如SqlSessionFactoryBuilder指定了特定的环境(即数据源);
* 则回来指定环境(数据源)的Environment目标,否则回来默认的Environment目标;
* 这种办法实现了MyBatis能够衔接多数据源
*/
private void environmentsElement(XNode context) throws Exception {
if (context != null)
{
if (environment == null)
{
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren())
{
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id))
{
//1.创立业务工厂 TransactionFactory
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
//2.创立数据源DataSource
DataSource dataSource = dsFactory.getDataSource();
//3. 结构Environment目标
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
//4. 将创立的Envronment目标设置到configuration 目标中
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
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目标
将上述的MyBatis初始化根本进程的序列图细化:
初始化办法 – 依据Java API
当然咱们能够运用XMLConfigBuilder手动解析XML装备文件来创立Configuration目标,代码如下:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 手动创立XMLConfigBuilder,并解析创立Configuration目标
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); // 看这儿
Configuration configuration = parser.parse();
// 运用Configuration目标创立SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// 运用MyBatis
SqlSession sqlSession = sqlSessionFactory.openSession();
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");
点击关注,第一时间了解华为云新鲜技能~