笔记学习自MyBatis技术内幕,做者的水平很高,虽然书里表面说的MyBatis源码,但其实是谈论设计模式的具体应用,强推!java
Java类型到Jdbc类型是怎么实现的?sql
MyBatis的类型转换器依赖于TypeHandler
接口,其中getResult
负责将Java类型转换成JdbcType类型,而setParameter
则反之编程
内置的抽象类类为BaseTypeHandler
,全部默认实现类都继承于它,基本是调用PreparedStatement
和ResultSet
方法来具体实现参数绑定/获取指定列值设计模式
TypeHandlerRegistry
负责管理MyBatis初始化阶段建立的全部已知TypeHandler
对象api
具体的是提供映射(真·Map对象),核心字段有数组
JDBC_TYPE_HANDLER_MAP:用于表示JdbcType
到TypeHandler
的惟一映射缓存
TYPE_HANDLER_MAP
:用于表示Type
到多个JdbcType
的TypeHandler
的映射(好比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依次检查,并从中挑出可用的)
该类中有两个字段defaultClassLoader
和systemClassLoader
,前者由系统指定,后者由ClassLoader.getSystemClassLoader()
提供
该ClassLoaderWrapper中的getClassLoaders(classLoader)
返回ClassLoader[]
数组,分别是
classLoader / defaultClassLoader / Thread.currentThread().getContextClassLoader() / getClass().getClassLoader() / systemClassLoader
不一样的类加载器具备不一样的访问权限,对于获取资源如URL getResourceAsURL(resource,classLoader[])
就会依据上面给出的类加载器顺序依次获取资源(失败后会再经过"/"+resource再次尝试)
数据源组件须要经过实现javax.sql.DataSource
接口来实现,MyBatis经过经典的工厂模式来提供两个实现类PooledDataSource
和UnpooledDataSource
,其对应的工厂类为实现DataSourceFactory
的PooledDataSourceFactory
和UnpooledDataSourceFactory
,其工厂接口(关注建立API)-工厂实现(关注建立逻辑)-产品接口(关注用户API)-产品实现(关注业务逻辑)的设计典范是十分规范的面向接口编程
在实现类中均封装好的注册JDBC驱动、创建Connection等模板
PooledDataSource
不直接管理javax.sql.Connection
对象,而是委托给PooledConnection
,它直接封装了Connection
对象及其代理(比方说当调用代理的close()时实际是调用PooledDataSource.pushConnection()
)
而且由PooledState
经过ArrayList<PooledConnection>
管理idle的链接
彷佛没啥好说的?也是个工厂实现
Cache
接口提供很是多的缓存实现装饰器,好比SoftCache
、LruCache
、SynchronizedCache
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实现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
,后面两个在前面已经讨论过细节
1.经过配置文件生成SqlSessionFactory对象,SqlSessionFactory生成SqlSession(openSession())
2.SqlSession接口定义执行SQL所需的方法
3.经过SqlSession对象执行配置中的SQL语句
4.经过SqlSession对象提交事务
5.关闭SqlSession