筆記學習自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