Mybatis 源码解析
- 动态代理 MapperProxy
- SQL 会话 SqlSession
- 执行器 Executor
- JDBC 处理器 StatementHandler
|
|
单例模式
单例模式是表示一个类只有一个实例,按照单例的范围可以分为线程内单例、进程内单例、集群内单例。
ErrorContext 这是一个线程级别的单例模式,MyBatis 使用它作为解析 xml 配置或执行 SQL 时的线程上下文信息,如当前正在解析的资源文件、当前执行的 SQL 等等
工厂模式
工厂模式用以创建多个类型相似的不同对象(同一个类的多个子类),又可以细分为简单工厂、工厂方法、抽象工厂。
SqlSessionFactory
SqlSession 表示 MyBatis 与数据库的一次会话,MyBatis 中默认的 SqlSession 是 DefaultSqlSession,MyBatis 使用 SqlSessionFactory 作为工厂创建 SqlSession,具体的设计模式为工厂方法模式,SqlSessionFactory 仅在 MyBatis 内部使用,并未留给用户扩展。
TransactionFactory
Transaction 表示在某次会话中,MyBatis 执行的一个事务,默认的实现是 JdbcTransaction,为了创建 Transaction,MyBatis 抽象出一个 TransactionFactory 作为工厂类,为了允许用户配置,因此设计为工厂方法模式。
DataSourceFactory
DataSource 是 JDBC 规范中用于获取 Connection 的类,MyBatis 内置了一些 DataSource,如 UnpooledDataSource、PooledDataSource。为了支持获取不同的 DataSource ,MyBatis 抽象出创建 DataSource 的 DataSourceFactory,为了允许用户进行扩展和配置,同样使用了工厂方法模式。
其他工厂
MapperProxyFactory:我们定义的 Mapper 为接口,为了可以直接使用,MyBatis 使用 MapperProxyFactory 作为简单工厂创建 Mapper 接口的代理 MapperProxy。
建造者模式
Environment.Builder Envrionment 是 MyBatis 执行 SQL 的环境,持有持有事务工厂 TransactionFactory 和数据源 DataSource。MyBatis 创建 Environment 使用的建造者模式代码如下。
- MappedStatement.Builder
- ParameterMapping.Builder
- Discriminator.Builder
- ResultMap.Builder
- CacheBuilder
SQLSessionFactoryBuilder 主要用来对 xml 或注解进行解析生成配置。
和经典的实现方式不同,SqlSessionFactoryBuilder 并非直接通过方法设置属性,而是委派 XMLConfigBuilder 解析 xml 配置,进而创建 SqlSessionFactory。其他很多与配置相关的建造者模式实现也是直接委派其他类解析配置或者直接解析配置。其他改进后的建造者模式主要包括如下。
- XMLConfigBuilder
- XMLMapperBuilder
- XMLScriptBuilder
- SqlSourceBuilder
- XMLStatementBuilder
代理模式
SQL 日志打印
为了打印 SQL 相关的日志,MyBatis 为 JDBC 规范中的各种类型提供了代理,在执行对应方法的时候就会进行日志打印。代理类包括如下
- ConnectionLogger:打印 Connection 类#prepareStatement或#prepareCall方法执行日志。
- reparedStatementLogger:打印 PreparedStatement 类执行的 SQL 及参数。
- StatementLogger:打印 Statement 类执行的 SQL。
- ResultSetLogger:打印 ResultSet 返回的记录信息。
以上都继承 BaseJdbcLogger 类并实现了 InvocationHandler 接口
插件实现
代理模式同样在 MyBatis 中的插件实现中有使用。自定义的插件需要实现 Interceptor,这个 Interceptor 会被放在 InterceptorChain 中。
在 MyBatis 执行 SQL 的生命周期中,InterceptorChain#pluginAll
会为生命周期中使用到的 ParameterHandler、ResultSetHandler、StatementHandler、Executor 创建代理对象,从而可以在生命周期中插入我们自定义的逻辑,如分页、数据库字段加密等。
|
|
生成接口实现
MyBatis 允许我们创建 Mapper 接口,然后 MyBatis 为我们的 Mapper 创建代理,底层仍然是调用了 SqlSession 的方法。
Mapper 接口的代理类为 MapperProxy,它由 MapperProxyFactory 通过简单工厂创建。
类加载处理
除了上述 MyBatis 中代理的使用场景,为了保证 DriverManager 中注册的 Driver 由系统类加载器加载,MyBatis 还为其内部使用到的 Drvier 提供了代理 DriverProxy。
装饰模式
Executor
- 抽象组件 Executor
- 具体组件 CachingExecutor
- 抽象装饰者 BaseExecutor
- 具体装饰者 SimpleExecutor,BatchExecutor,ReuseExecutor
数据源
MyBatis 内置了不支持池的数据源 UnpooledDataSource 和支持池的数据源 PooledDataSource。由于这两者部分实现类似,因此 PooledDataSource 使用装饰器模式,对 UnpooledDataSource 进行增强,提供了池,以便减少反复获取释放连接的资源消耗。
缓存
由于 MyBatis 事先并不知道用户会进行哪些配置,如果为各种配置的组合创建不同的缓存类,那么将导致 MyBatis 中存在较多的的缓存类,并且也会导致实现的复杂。为了解决这个问题,MyBatis 使用装饰器模式,通过为原有 Cache 进行装饰,以支持不同的参数,这样不同的参数就可以创建出不同的 Cache。
支持日志打印的 LoggingCache
责任链模式
责任链模式将请求的发送与接收者解耦,由链上的每个对象处理请求。
MyBatis 使用责任链模式主要用来实现插件,在 MyBatis 执行 SQL 的生命周期中,将插件组成一个链,在特定的生命周期中执行额外操作。
|
|
模板方法
模板方法定义了算法的骨架,将算法中的某些步骤推迟到子类来实现。主要用于复用和扩展。
MyBatis 对模板方法的使用主要有两块,包括如下。
- BaseExecutor:Executor 负责组装 SQL 执行所需的的各模块,完成整个流程。为了复用代码,把重复的逻辑提取到模板方法中。
- BaseTypeHandler:TypeHandler 用于设置 JDBC 中 SQL 的参数,以及从 ResultSet 中获取值。
迭代器模式
迭代器模式用于遍历对象,大多数编程语言都使用迭代器模式实现对集合对象的遍历。
MyBatis 中的迭代器和传统的迭代器模式实现不太相同,它主要用迭代器实现对嵌套的属性遍历。MyBatis 中使用 PropertyTokenizer 表示嵌套的属性。
组合模式
|
|
XMLScriptBuilder 中组合
适配器模式
MyBatis的日志功能源码包logging就是适配器模式的应用,主要是为了将市场的各种日志插件,转换为MyBatis的日志接口,统一使用。
Slf4jImpl 实现了 Log 接口。Slf4jImpl 就是 Apdater 类,Log 接口就是 Target。 Slf4jLoggerImpl 就是一个 Adaptee
|
|