MyBatis游玩

笔记学习自MyBatis技术内幕,做者的水平很高,虽然书里表面说的MyBatis源码,但其实是谈论设计模式的具体应用,强推!java

基础支持

类型转换

Java类型到Jdbc类型是怎么实现的?sql

MyBatis的类型转换器依赖于TypeHandler接口,其中getResult负责将Java类型转换成JdbcType类型,而setParameter则反之编程

内置的抽象类类为BaseTypeHandler,全部默认实现类都继承于它,基本是调用PreparedStatementResultSet方法来具体实现参数绑定/获取指定列值设计模式

TypeHandlerRegistry负责管理MyBatis初始化阶段建立的全部已知TypeHandler对象api

具体的是提供映射(真·Map对象),核心字段有数组

JDBC_TYPE_HANDLER_MAP:用于表示JdbcTypeTypeHandler的惟一映射缓存

TYPE_HANDLER_MAP:用于表示Type到多个JdbcTypeTypeHandler的映射(好比String会对应于char和varchar)session

好比类型为Map<JdbcType,TypeHandler<?>>JDBC_TYPE_HANDLER_MAP字段(实质为EnumMap),当从结果集获取数据时,依靠这个还实现Jdbc类型到Java类型的转换mybatis

而关键的register的常见重载方法有(Type,JdbcType,TypeHandler)的入参,具体注册顺序为app

1.检测javaType是否为空,不管是否为空均加入到ALL_TYPE_HANDLERS_MAP(key为handler.getClass())

2.若是非空,从TYPE_HANDLER_MAP中经过javaType得到对应的Handler的Map

3.若是没有对应Handler的Map,则经过直接新建一个空的HashMap并加入到TYPE_HANDLER_MAP

4.在对应的handler的Map加入(jdbcType,handler)键值对

这样实现了单个javaType对应多个jdbcType的handler映射注册,在此以后要得到typeHandler可经过getTypeHandler(type,jdbcType)获得,其实就是跑上面的Map的对应键值便可

类型别名的实现?

MyBatis经过TypeAliasRegistry完成表/列名的别名注册和管理

具体是经过Map<String,Class<?>> TYPE_ALIASES字段以及registerAlias()实现,就是个get检查有没有而后再put进去的过程(冲突会抛出异常!)。。

日志

MyBatis经过适配器模式实现对不一样的日志接口/实现(Adaptee)的兼容,其内部使用接口为Log(适配器中的Target),由LogFactory来实现适配过程(Adapter)

资源加载

MyBatis封装了ClassLoaderWrapper做为ClassLoader的包装器,使用起来和ClassLoader一致,但可调整ClassLoader使用顺序(多个ClassLoader依次检查,并从中挑出可用的)

该类中有两个字段defaultClassLoadersystemClassLoader,前者由系统指定,后者由ClassLoader.getSystemClassLoader()提供

该ClassLoaderWrapper中的getClassLoaders(classLoader)返回ClassLoader[]数组,分别是

classLoader / defaultClassLoader / Thread.currentThread().getContextClassLoader() / getClass().getClassLoader() / systemClassLoader

不一样的类加载器具备不一样的访问权限,对于获取资源如URL getResourceAsURL(resource,classLoader[])就会依据上面给出的类加载器顺序依次获取资源(失败后会再经过"/"+resource再次尝试)

DataSource

数据源组件须要经过实现javax.sql.DataSource接口来实现,MyBatis经过经典的工厂模式来提供两个实现类PooledDataSourceUnpooledDataSource,其对应的工厂类为实现DataSourceFactoryPooledDataSourceFactoryUnpooledDataSourceFactory,其工厂接口(关注建立API)-工厂实现(关注建立逻辑)-产品接口(关注用户API)-产品实现(关注业务逻辑)的设计典范是十分规范的面向接口编程

在实现类中均封装好的注册JDBC驱动、创建Connection等模板

PooledDataSource不直接管理javax.sql.Connection对象,而是委托给PooledConnection,它直接封装了Connection对象及其代理(比方说当调用代理的close()时实际是调用PooledDataSource.pushConnection()

而且由PooledState经过ArrayList<PooledConnection>管理idle的链接

事务管理

彷佛没啥好说的?也是个工厂实现

缓存

Cache接口提供很是多的缓存实现装饰器,好比SoftCacheLruCacheSynchronizedCache

Cache中指定的key CacheKey不是一个简单的String,内部封装了multiplier/hashCode/checkSum/count等用于重写hashCode()equals()的字段,还有List<Object> updateList会记录多种影响缓存项的因素(既可经过多个对象组成一个key),好比MappedStatement的id/查询结果集的范围/查询使用的SQL/传递到SQL的参数,每次update(obj)到一个key时会判断是不是数组,若是是则添加多个内部对象到cacheKey,无论如何都是经过doUpdate(obj)来具体更新,四个字段更新:count++,checkSum+=baseHashcode,baseHashCode*=count,hashCode=multiplier*hashCode+baseHashCode,最后把obj放入到updateList中,判断key是否相等则依次按照上述字段进行对比,无可奈何才用updateList的元素比较

Binding

Binding实现xml/注解到接口的绑定(就是一堆Mapper就能实现执行SQL的原理)

从而实现SQL到Java层的对接

XxxMapper mapper = session.getMapper(XxxMapper.class);

Xxx obj = mapper.do(...);

POJO到mapper的实现?

就是个面向接口的动态代理,所以写mapper时声明interface

解析器

解析器指对XML的处理,MyBatis使用DOM解析方式,具体使用到XPath解析并将其封装到XPathParser

反射模块

MyBatis提供封装好的reflection

核心处理

配置解析

MyBatis初始化工做为加载并解析mybatis-config.xml配置文件、映射配置文件和相关的注解

其初始化入口为SqlSessionFactoryBuilder.build(reader,enviroonment,properties)

具体的会先尝试建立XMLConfigBuilder parser,若是成功则委托给build(parser.parse())

XMLConfigBuilder就是一个BaseBuilder抽象类的具体实现

BaseBuilder包含一个全局惟一配置configuration,别名标记typeAliasRegistry,handler注册中心typeHandlerRegistry,后面两个在前面已经讨论过细节

外部API流程

1.经过配置文件生成SqlSessionFactory对象,SqlSessionFactory生成SqlSession(openSession())

2.SqlSession接口定义执行SQL所需的方法

3.经过SqlSession对象执行配置中的SQL语句

4.经过SqlSession对象提交事务

5.关闭SqlSession

相关文章
相关标签/搜索