Mybatis整体架构
MyBatis的整体架构分为三层,分别是基础支持层、核心处理层和接口层
- SqlSession
1、SqlSession是Mybatis最重要的构建之一,可以简单的认为Mybatis一系列的配置目的是生成类似 JDBC生成的Connection对象的SqlSession对象,这样才能与数据库开启“沟通”,通过SqlSession可以实现增删改查
2、SqlSession 是门面设计模式的经典运用,SqlSession实现增删改查,全靠Executor 来进行执行
3、SqlSession 是一个线程不安全的类,在多线程情况下应保证每一个线程使用不同的 SqlSession
4、SqlSession 是 Connection 对应的高级封装
Mybatis 初始化流程
// 资源路径 resource/mybatis-config.xml
String resource = "mybatis-config.xml";
// 包装成 InputStream
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过构建者模式创建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 初始化 SqlSessionFactory 时序图
- 调用SqlSessionFactoryBuilder对象的build(inputStream)方法;
- SqlSessionFactoryBuilder会根据输入流inputStream等信息创建XMLConfigBuilder对象;
- SqlSessionFactoryBuilder调用XMLConfigBuilder对象的parse()方法;
- XMLConfigBuilder对象返回Configuration对象;
- SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;
- SqlSessionFactoryBuilder返回 DefaultSessionFactory对象给Client,供Client使用。
- 初始化涉及到的几个对象
1、SqlSessionFactoryBuilder : SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式
2、Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息
3、SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式
4、XmlConfigParser :负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory
解析 XML
1、Document:将 XML 数据在内存中解析成一个树,通过对树的操作来操作XML。
2、SAX:SAX不用将整个文档加载到内存,基于事件驱动的API(Observer模式),他按照xml文件的顺序一步一步的来解析
3、XPath:MyBatis使用XPath技术解析XML文档,MyBatis提供的XPathParser类对XPath的进行了封装,提供了更为友好的方法以方便用户使用。
XPathParser
public class XPathParser {
/**
* Document对象
*/
private final Document document;
/**
设置是否启用DTD验证
*/
private boolean validation;
/**
* 用于加载本地的DTD文件
*/
private EntityResolver entityResolver;
private Properties variables;
// 用来解析XML文档的XPath对象
private XPath xpath;
}
1、XMLConfigBuilder 会将 mybatis-config.xml 以及对应的 Mapper 配置文件转换成 Document 对象
2、将 mybatis-config.xml 配置定义文件 dtd 转换为 EntityResolver
- 代码 XMLConfigBuilder
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 {
//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);
}
}
注意:1、之后XMLConfigBuilder调用parse()方法:会从XPathParser中取出
节点对应的Node对象,然后解析此Node节点的子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers
2、注意解析顺序需要与 mybatis-config.xml 的配置顺序相同
3、第 10 部会解析 mappers 节点,并根据对应的 url , packing , resource 等方式绑定对应的 *Mapper.xml,并配置到 Configuration 中
设置 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;
}