对于大多数开发框架在使用之前都会经历 配置 ----> 初始化 过程,Mybatis也不例外。本章将通过以下几点深入源码详细讲解Mybatis初始化过程。
1.Mybatis初始化做了什么
2.Mybatis解析XML配置文件创建Configuration对象过程
1. Mybatis初始化做了什么?
/**
* <p> In-Depth Study Mybatis with one</p>
* @author jackcheng1117@163.com
*/
public class DemoApplication {
public static void main(String[] args) throws IOException {
//获取配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化Mybatis
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
}
}
Mybatis基本初始化流程图:
Mybatis初始化源码流程:
1. SqlSessionFactoryBuilder获取Mybatis配置文件流传递给XMLConfigBuilder对象
//Mybatis初始化入口
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//将配置流传递给XMLConfigBuilder解析XML文件,初始化Mybatis默认配置项
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//parser.parse() : 初始化XML配置文件中配置
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.
}
}
}
2.创建XPathParser对象将XML配置文件解析为Docment配置项
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
//解析XML文件并生成Document
this.document = createDocument(new InputSource(inputStream));
}
3.初始化Mybatis配置项,生成Configuration对象
//初始化Mybatis默认配置
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//初始化Mybatis默认配置项
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
//XMLConfigBuilder parse方法 : 初始化XML配置文件中配置项
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//初始化XML中配置的配置
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
4. Mybatis初始化完毕,返回SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
综上所述,Mybatis初始化大致如下:
1. 调用 SqlSessionFactory的 build(InputStream inputStream) 方法
2. 创建 XPathParser对象将XML解析为 Document
3. 创建 XMLConfigBuilder对象,通过super(new Configuration) 初始化 Mybatis 默认配置
4. 调用 XMLConfigBuilder 对象的 parse() 方法初始化XML中配置项,并返回Configuration对象
5. 使用配置好的Configuration对象创建 SqlSessionFactory实现类DefaultSqlSessionFactory
总结:
初始化Mybatis的过程其实就是构建 Configuration 这个对象,Configuration对象包含了Mybatis运行所需要的所有配置项。
MyBatis采用了一个非常直白和简单的方式---使用 org.apache.ibatis.session.Configuration 对象作为一个所有配置信息的容 器,Configuration对象的组织结构和XML配置文件的组织结构几乎完全一样(当然,Configuration对象的功能并不限于此,它还负责创建一些MyBatis内部使用的对象,如Executor等,这将在后续的文章中讨论)。如下图所示:
Mybatis初始化有两种方式:
基于XML配置文件:
基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
基于Java API:
这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,手动创建Configuration对象,然后将配置参数set 进入Configuration对象中
2. Mybatis解析XML配置文件创建Configuration对象过程
章节一已将列出了Mybatis初始化的完整流程,Mybatis初始化时期本质上是初始化配置(即初始化Configuration对象),本章将详细讲解Mybatis是如何解析XML配置并初始化到Configuration的。
Step1: 初始化默认配置项
当执行入口方法 SqlSessionFactoryBuilder.build(InputStream inputStream, String environment, Properties properties)时,
首先会实例化出 XMLConfigBuilder,实例化过程中的 super(new Configuration()); 会进行初始化Mybatis默认配置项(即初始化Congiguration对象)
new Configuration()主要执行的工作是:
1. 初始化配置容器
2. 注册配置实现类
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
Step2:初始化XML自定义配置项
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析XML自定义配置节点,并将配置映射到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);
}
}
以上就是本文 《深入理解mybatis原理》 Mybatis初始化机制详解 的全部内容,
上述内容如有不妥之处,还请读者指出,共同探讨,共同进步!
@author : jackcheng1117@163.com