mybatis初始化源码解析

pull/8/head
quanhengf 6 years ago
parent 1c6864501e
commit ace1e8f724

@ -24,8 +24,10 @@
### SpringJDBC
### Spring事务
### Spring源码故事瞎编版
- [面筋哥 IoC 容器的一天(上)](/docs/Spring/IoC/面筋哥IoC容器的一天(上).md)
@ -37,6 +39,8 @@
- [缓存模块](docs/Mybatis/基础支持层/4、缓存模块.md)
### 核心处理层
- [MyBatis初始化](docs/Mybatis/核心处理层/1、MyBatis初始化.md)
- [ResultSetHandler](docs/Mybatis/核心处理层/2、ResultSetHandler.md)
- [Executor组件](docs/Mybatis/核心处理层/3、Executor组件.md)
## Netty
### IO
@ -46,6 +50,8 @@
## Redis
## Tomcat
## 学习心得
### 个人经验
- [初级开发者应该从 spring 源码中学什么](docs/学习心得/个人经验/初级开发者应该从spring源码中学什么.md)

@ -0,0 +1,203 @@
和spring框架的IoC容器初始化一样mybatis也会通过定位、解析相应的配置文件完成自己的初始化。mybatis的配置文件主要有mybatis-config.xml核心配置文件及一系列映射配置文件另外mybatis也会根据注解进行配置。
## 1 BaseBuilder
mybatis初始化的主要内容是加载并解析mybatis-config.xml配置文件、映射配置文件以及相关的注解信息。mybatis的初始化入口是SqlSessionFactoryBuilder的build()方法。
```java
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
/**
* build方法的主要实现
*/
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// SqlSessionFactory会创建XMLConfigBuilder对象来解析mybatis-config.xml配置文件
// XMLConfigBuilder继承自BaseBuilder抽象类顾名思义这一系的类使用了 建造者设计模式
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 解析配置文件的内容 到Configuration对象根据到Configuration对象
// 创建DefaultSqlSessionFactory对象然后返回
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
// 关闭配置文件输入流
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
```
BaseBuilder中的核心字段如下
```java
public abstract class BaseBuilder {
// 保存了mybatis的几乎所以核心配置信息全局唯一
protected final Configuration configuration;
// 在mybatis-config.xml中可以通过<typeAliases>标签定义别名
protected final TypeAliasRegistry typeAliasRegistry;
// 在mybatis-config.xml中可以通过<typeHandlers>标签添加自定义TypeHandler
// TypeHandler用于完成JDBC数据类型与Java类型的相互转换所有的TypeHandler
// 都保存在typeHandlerRegistry中
protected final TypeHandlerRegistry typeHandlerRegistry;
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
}
```
BaseBuilder中的typeAliasRegistry和typeHandlerRegistry字段均来自于configuration通过BaseBuilder的构造方法可以看到详细内容。
## 2 XMLConfigBuilder
XMLConfigBuilder是BaseBuilder的众多子类之一主要负责解析mybatis-config.xml配置文件。它通过调用parseConfiguration()方法实现整个解析过程其中mybatis-config.xml配置文件中的每个节点都被封装成了一个个相应的解析方法parseConfiguration()方法只是依次调用了这些解析方法而已。
```java
public class XMLConfigBuilder extends BaseBuilder {
// 标记是否解析过mybatis-config.xml文件
private boolean parsed;
// 用于解析mybatis-config.xml的解析器
private final XPathParser parser;
// 标识<environment>配置的名称,默认读取<environment>标签的default属性
private String environment;
// 创建并缓存Reflector对象
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
/**
* 解析的入口调用了parseConfiguration()进行后续的解析
*/
public Configuration parse() {
// parsed标志位的处理
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 在mybatis-config.xml配置文件中查找<configuration>节点,并开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// 根据root.evalNode("properties")中的值就可以知道具体是解析哪个标签的方法咯
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中的标签很多所以相对应的解析方法也很多这里挑几个比较重要的标签进行分析。
### 2.1 解析&lt;typeHandlers&gt;标签
```java
private void typeHandlerElement(XNode parent) throws Exception {
if (parent != null) {
// 处理<typeHandlers>下的所有子标签
for (XNode child : parent.getChildren()) {
// 处理<package>标签
if ("package".equals(child.getName())) {
// 获取指定的包名
String typeHandlerPackage = child.getStringAttribute("name");
// 通过typeHandlerRegistry的register(packageName)方法
// 扫描指定包中的所有TypeHandler类并进行注册
typeHandlerRegistry.register(typeHandlerPackage);
} else {
// Java数据类型
String javaTypeName = child.getStringAttribute("javaType");
// JDBC数据类型
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
// 注册
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
```
### 2.2 解析&lt;environments&gt;标签
```java
/**
* mybatis可以配置多个<environment>环境,分别用于开发、测试及生产等,
* 但每个SqlSessionFactory实例只能选择其一
*/
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
// 如果未指定XMLConfigBuilder的environment字段则使用default属性指定的<environment>环境
if (environment == null) {
environment = context.getStringAttribute("default");
}
// 遍历<environment>节点
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
// 实例化TransactionFactory
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
// 创建DataSourceFactory和DataSource
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
// 创建的Environment对象中封装了上面的TransactionFactory对象和DataSource对象
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
// 为configuration注入environment属性值
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
```
### 2.3 解析&lt;databaseIdProvider&gt;标签
```java
```
### 2.4 解析&lt;mappers&gt;标签
```java
```

@ -1,10 +1,13 @@
## 六大原则
1. 单一职责:一个类只负责唯一一项职责
2. 依赖倒置:即面向接口编程,系统的高层模块(顶层接口、顶层抽象类等)不应该依赖底层模块(具体实现类),当需求发生变化时,对外接口不变,只要提供新的实现类即可。
3. 接口隔离:尽量设计出功能单一的接口,避免实现类实现很多不必要的接口方法
4. **开放-封闭:对扩展开放,对修改关闭**,本原则是设计模式的终极目标
5. 迪米特法则:尽量减少类之间的耦合性
6. 里氏替换:继承体系的设计要合理
## 装饰器模式

Loading…
Cancel
Save