MyBatis架构图
MyBatis 架构
MyBatis 依赖的 jar 不多,而且代码行数也没多少,其中使用了大量的设计模式,值得好好学习。下图是 MyBatis 的一张架构图,来自Java 框架篇—Mybatis 入门。
Mybatis 的功能架构分为三层:
- API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
MyBatis 整个项目的包结构如下:
.
└── org
└── apache
└── ibatis
├── annotations
├── binding
├── builder
├── cache
├── cursor
├── datasource
├── exceptions
├── executor
├── io
├── jdbc
├── logging
├── mapping
├── parsing
├── plugin
├── reflection
├── scripting
├── session
├── transaction
└── type
1. 兵马未动,日志先行
org.apache.ibatis.logging
org.apache.ibatis.logging.commons
org.apache.ibatis.logging.jdbc
org.apache.ibatis.logging.jdk14
org.apache.ibatis.logging.log4j
org.apache.ibatis.logging.log4j2
org.apache.ibatis.logging.nologging
org.apache.ibatis.logging.slf4j
org.apache.ibatis.logging.stdout
2. 异常
org.apache.ibatis.exceptions
3. 缓存
org.apache.ibatis.cache
org.apache.ibatis.cache.decorators
org.apache.ibatis.cache.impl
4. 解析
org.apache.ibatis.parsing
xml 解析,${} 格式的字符串解析
源码分析可以参考 http://www.cnblogs.com/sunzhenchao/p/3161093.html
5. 类型处理器
org.apache.ibatis.type
实现 java 和 jdbc 中的类型之间转换
源码分析可以参考 http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3009431.html
6.IO
org.apache.ibatis.io
通过类加载器在 jar 包中寻找一个 package 下满足条件 (比如某个接口的子类) 的所有类
7. 反射
org.apache.ibatis.reflection
org.apache.ibatis.reflection.factory
org.apache.ibatis.reflection.invoker
org.apache.ibatis.reflection.property
org.apache.ibatis.reflection.wrapper
可以参考 MetaObjectTest 来跟踪调试,基本上用到了 reflection 包下所有的类
8. 数据源
org.apache.ibatis.datasource
org.apache.ibatis.datasource.jndi
org.apache.ibatis.datasource.pooled
org.apache.ibatis.datasource.unpooled
9. 事务
org.apache.ibatis.transaction
org.apache.ibatis.transaction.jdbc
org.apache.ibatis.transaction.managed
10. 会话
org.apache.ibatis.session
org.apache.ibatis.session.defaults
11.jdbc 单元测试工具
org.apache.ibatis.jdbc
12. 构建
org.apache.ibatis.builder
org.apache.ibatis.builder.annotation
org.apache.ibatis.builder.xml
13. 映射
org.apache.ibatis.mapping
14. 脚本
org.apache.ibatis.scripting
org.apache.ibatis.scripting.defaults
org.apache.ibatis.scripting.xmltags
15. 注解
org.apache.ibatis.annotations
16. 绑定
org.apache.ibatis.binding
17. 执行器
org.apache.ibatis.executor
org.apache.ibatis.executor.keygen
org.apache.ibatis.executor.loaderorg.apache.ibatis.executor.loader.cglib
org.apache.ibatis.executor.loader.javassist
org.apache.ibatis.executor.parameter
org.apache.ibatis.executor.result
org.apache.ibatis.executor.resultset
org.apache.ibatis.executor.statement
18. 插件
org.apache.ibatis.plugin
注释①
mybatis 通过SqlSessionFactoryBuilder作为入口,通过传入配置文件,使用了BaseBuilder实现类进行配置文件解析,具体实现类是 XMLConfigBuilder,在这里 mybatis 对配置的项进行了全面解析,只不过不是所有的解析都放在了 XMLConfigBuilder,XMLConfigBuilder 解析了二级节点,并作为一个总入口,还有另外几个类继承了 BaseBuilder,用于解析不同的配置。而解析到的配置项信息,基本都保存在了 Configuration 这个类,可以看到多处地方依赖到它。
之后通过配置获取到 SqlSessionFactory,可以看到 SqlSessionFactoryBuilder 提供了一个 build 方法,就是返回 SqlSessionFactory 的。
注释②
而 SqlSessionFactory 只是一个接口,默认实现有 DeaultSqlSessionFactory。通过 SqlSessionFactory.openSession 的几个多态方法,可以获取到 SqlSession。
注释③
而 SqlSession 也只是一个接口,怎么理解 SqlSession 呢,其实 Session 即是一次会话,假如我们把某次请求与数据库连接 Connection 的交互,看成是一次会话,那就可以理解 SqlSession 了。SqlSession 是请求与数据库的一次交互,交互完成之后,Session 则结束,但 Session 结束不代表数据库连接也关闭,只是这次会话终止了,但是数据库连接依旧是返回给连接池。
这里的 SqlSession 即是对一次交互信息的封装,请求可以通过 SqlSession 的方法(如图:CRUD )进行操作,而数据库连接,依旧由 SqlSessionFactory 注入。
注释②
如图我们可以看到 SqlSessionFactory 获取到 TransactionFactory,一个事务的工厂类接口,而通过这个工厂具体实现类可以产生多个事务 Transaction(具体参考 ManagedTransactionFactory),Transaction 抽象了一个方法 getConnection,通过这个方法我们可以获取到不同事务级别的 connection。mybatis 的代码是这样的:
ManagedTransaction.java
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug(“Opening JDBC Connection”);
}
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
注释④
这个时候可能大家觉得万事俱备了,SqlSession 都定义好了 CRUD 方法了, 那它也会帮忙将语句扔给 Connection 操作,其实不然。这里 mybatis 还抽象了接口 Execute。
Execute 才是真正将 sql 与 Connection 打交道的地方。
图中我们可以看到 Execute 有四个实现类,通过名称我们不难发现它们各自的用途,例如 CachingExecutor.java,mybatis 默认是有缓存的,就是通过这个类实现的。
还有一个点,每个 Execute 实现类中,都可以发现有这样一个定义和构造方法
private Executor delegate;
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
所以这里我们也可以看到,其实 Executor 有个链结构,一步一步往下执行,所以在真正执行查询时,外面是嵌套了一层 CachingExecutor,证据在这里。
- public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
- executorType = executorType == null ? defaultExecutorType : executorType;
- executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
- Executor executor;
- if (ExecutorType.BATCH == executorType) {
- executor = new BatchExecutor(this, transaction);
- } else if (ExecutorType.REUSE == executorType) {
- executor = new ReuseExecutor(this, transaction);
- } else {
- executor = new SimpleExecutor(this, transaction);
- }
- if (cacheEnabled) {
- executor = new CachingExecutor(executor, autoCommit);
- }
- executor = (Executor) interceptorChain.pluginAll(executor);
- return executor;
- }
在 Execute 中,还有更深层的执行逻辑,这个后面文章继续分析。
转载请注明出处:http://sukerz.scse.cn/index.php/2016/02/01/mybatis-framework/