mybatis的几点认识
目录
- MyBatis的初始化做了什么
- MyBatis的创建过程
- 手动加载
- 设计的几个主要设计模式
背景
简单啰嗦一下背景
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
- iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
-
自己绘制的图将就着看,重要的是意思O(∩_∩)O哈哈~
初始化做了什么
- MyBatis基于XML配置文件创建Configuration对象的过程 手动加载XML配置文件创建Configuration对象完成初始化,创建并使用SqlSessionFactory对象 ,其实这里已经涉及到设计模式了,最后会讲。
- 对于任何框架而言,在使用前都要进行一系列的初始化,就是使用对象要初始化一样。框架的初始化,无非是加载自己运行时所需要的配置信息。
详细配置
-properties 属性
-settings 设置
- typeAliases 类型命名
- typeHandlers 类型处理器
- bjectFactory 对象工厂
- plugins 插件
- environments 环境
- environment 环境变量
- transactionManager 事务管理器
- dataSource 数据源
映射器
- MyBatis配置信息会配置在XML配置文件中,这些信息被加载进入MyBatis内部。使用 org.apache.ibatis.session.Configuration 对象作为一个所有配置信息的容器,why?
- 因为Configuration对象的组织结构和XML配置文件的组织结构几乎完全一样。
- 然后MyBatis根据初始化好Configuration信息,这时候用户就可以使用MyBatis进行数据库操作了
**到这里大家可能都知道了,其实MyBatis初始化的过程,就是创建 Configuration对象的过程。 **
那么初始化的方式都有哪些:
- 基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
- 基于Java API:这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,手动创建Configuration对象,然后将配置参数set 进入Configuration对象中
使用MyBatis的简单例子分析MyBatis是怎样完成初始化和初始化内容:
String resource = "mybatis的mapper文件名字.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//第一个是语句,第二个是对应的实体类
sqlSession.selectList("select * from analysis_Report",AnalysisReport.class);
配着对应的流程图 |
---|
重点:
- SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 为什么?Because那个configuration的创建过程就在里面
- 初始化基本过程: SqlSessionFactoryBuilder根据传入的数据流生成Configuration 对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。
- 看一下源码,经过抽取的部分源码,并加上响应注释方便理解
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//1.创建XMLConfigBuilder对象用来解析XML配置文件,生成Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//2.讲XML配置文件的信息解析成Java对象Configuration对象
Configuration config = parser.parse();
//3.根据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.
}
}
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//从此可以看出,mybatis内部通过Configuration对象来创建SqlSessionFactory,
//程序员们可以自己通过API构造好Configuration对象或者再加一些别的自定义的东西都可以
//然后调用此方法创建SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
创建Configuration对象的过程在哪里?
- 在parse()方法里! XMLConfigBuilder会将XML配置文件的信息转换 为Document对象,而XML配置定义文件DTD转换成XMLMapperEntityResolver对 象,然后将二者封装到XpathParser对象中,XpathParser的作用是提供根据Xpath表 达式获取基本的DOM节点Node信息的操作。
- 解析node节点信息:
- 解析此Node节点的子Node:(configuration配置的东西) properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers
- 解析此Node节点的子Node:(configuration配置的东西) 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;
}
//解析 "/configuration"节点下的子节点信息,然后将解析结果设置到configuration对象中
private void parseConfiguration(XNode root) {
try {
//1.首先处理properties节点
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
propertiesElement(root.evalNode("properties"));
loadCustomVfs(settings);
//2.处理typeAliases
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
//3.处理objectFactory
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//4.处理settings
settingsElement(settings);
// 5.处理environments的节点
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);
}
}
如何将解析出来的值设置到configuration中??
举个栗子,将environments的信息解析出来,设置到Configuration对象 ,Look!!!
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类最后的涉及模式会提到,不懂的朋友可以去查一下
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
//4.将创建的Environment对象设置到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对象中,最后返回configuration对象。
- 流程图可以参考以下面的:
注意:解析XML配置文件子节点<mappers>的方法mapperElements(root.evalNode("mappers")), 它将解析我们配置的Mapper.xml配置文件,Mapper配置文件可以说是MyBatis的核心,MyBatis的特性和理念都体现在此Mapper的配置和设计上 解析environments节点,并将结果设置到Configuration对象中
手动加载XML配置文件
这个再上面的代码示例中展示过了,只不过,在手动加载过程会有一些其他自定义的代码
上面代码中涉及到的涉及模式:
SqlSessionFactoryBuilder:
- SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式 Configuration
SqlSessionFactory:
- SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式 XmlConfigParser
XmlConfigParser :
- 负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory
设计模式(主要常见)
建议对这些不熟悉的,多去看一下设计模式,一定要熟练
下面主要说一下Builder模式
- 用代码说明
- SqlSessionFactory的创建
- 还有就是在解释mybatis如何解析那些节点然后存到configuration对象中时提到的environment节点,同样是builder
XMLConfigParser解析配置文件节点
在Environment内部,定义了静态内部Builder类:
总结
其实mybatis内部还有很多东西,今天只是分析了一下mybatis初始化的内容,希望对大家有帮助!!