一,簡述
mybatis的作用就是操作資料庫,其實就是封裝參數,生成sql,執行sql,封裝結果,其實基本就是這幾個大的步驟,mybatis和spring是怎麼整合的呢,以及如何一步一步執行的,具體請看下面原理分析
二,源碼分析
2.1:SqlSessionFactoryBean
具體是在mybatis-spring整合包中,SqlSessionFactoryBean是加載mybatis配置檔案以及生成sqlSession的入口
2.2:FactoryBean
spring源碼有所了解的應該清楚這個factoryBean是一個生成特殊複雜的bean,以及和beanFactory的區:别,factoryBean中的一個重要的方法就是getObject方法,其實就是根據這個方法傳回一個特殊的自定義的bean對象,而且bean建立的時候,會建立一個&sqlSessionFactoryBean 和sqlSessionFactory對象,就是會建立本身bean攜帶&和getObject傳回的對象,而且getObject是使用的時候才會被調用的,使用的時候才會建立這個bean交給spring來管理
調用getObejct擷取sqlsessionfactory對象
public SqlSessionFactory FactoryBean() throws Exception {
if (this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
建立一個DefaultSqlSessionFactory,是以在何時建立的,就在這裡
以上就是和spring結合情況下,建立出來sqlSessionFactory的過程,其實就是建立一個SqlSessionFactoryBean對象,然後調用getObject的方法,就可以做到加載mybatis的配置以及資料的封裝的,以及擷取一個sqlSessionFactory對象,交個spring來管理
2.3:Spring中建立SqlSessionFactory對象
建立一個SqlSessionFactory,具體代碼執行的邏輯如下,其實就是做了一些資料的封裝,并調用getObject的方法,然後交給spring管理
2.4:spring-boot建立SqlSessionFactory對象
MybatisAutoConfiguration
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
//還是這個對象SqlSessionFactoryBean 來處理的,最後還是getObejct擷取的
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
this.applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.typeHandlers)) {
factory.setTypeHandlers(this.typeHandlers);
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
Set<String> factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
factory.setScriptingLanguageDrivers(this.languageDrivers);
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
defaultLanguageDriver = this.languageDrivers[0].getClass();
}
}
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}
this.applySqlSessionFactoryBeanCustomizers(factory);
//具體還是在這裡做出來的
return factory.getObject();
}
2.5:SqlSessionTemplate建立
MybatisAutoConfiguration中SqlSessionTemplate中建立
2.6:SqlSessionTemplate建立
建立SqlSessionTemplate 的時候,SqlSessionFactory為上文提到的DefaultSqlSessionFactory,SqlSession為這裡生成的代理對象,繼續根據代理對象是哪一個呢?
SqlSessionInterceptor
代理對象為這個類,看一下裡面的invoke方法
invoke
代理調用
getSqlSession
擷取sqlSession
openSession
擷取Executor
newExecutor
InterceptorChain鍊執行
pluginAll
目标的增強
小結:
源碼看到了這裡,基本是生成了sqlSessionFactrory,SqlSessionTemplate,以及SqlSession(其實是代理),以及代理對象的invoke的執行,基本就是一些後續執行的前提,是以這些bean的建立基本都應該有所了解了
三,mappper的代理對象生成
在調用的時候,我們隻是寫了一個mapper接口,并未寫實作,但是mapper中的方法和xml中的方法都是對應的,會将mapper全類名接口+方法名作為key存放在map中,每一個都是一個MappedStatement對象,存放在configuration的全局配置中,根據key擷取到MappedStatement對象,根據代理對象執行相應的邏輯
MapperScannerConfigurer
postProcessBeanDefinitionRegistry
ClassPathMapperScanner 進行掃描,this.basePackage是掃描的包,一般就是mapper接口所在的包,springboot中是預設啟動類目前包下的類被掃描 com.clover.**.mapper
scan
doScan
執行的含義就是生成bean對象
processBeanDefinitions
修改beanClass為MapperFactoryBean.class,這樣建立對象的時候,就會調用MapperFactoryBean中的方法
執行afterPropertiesSet方法,然後就是往cinfiguration中添加mapper接口對象
MapperFactoryBean
實作了FactoryBean,擷取mapper的時候,調用getobject方法,擷取代理對象
getMapper
newInstance
擷取mapper的代理對象,都是MapperProxy進行的代理,是以到此為止,就可以知道,啟動的時候,已經做到了mapper的對象是從MapperProxy代理對象進行跟蹤進行的
三,調用執行代理對象mapperProxy
MapperProxy
invoke
每一個mapper調用方法的時候,就會調用invoke執行,然後調用到MapperMethod的excute方法,根據類型執行相應的增删改查
MapperMethod
execute
判斷類型,其實這個類型就是mapperXml定義的标簽以及id和與之對應的方法名一一對應的,到了這裡,可能就比較熟悉了,因為對于sql的增删改查相比都是比較的熟悉,這裡其實就是下面可以猜測到的,拼裝sql,和參數,然後執行sql,傳回結果,處理傳回結果
比如一個executeForMany為例
SqlSessionTemplate調用selectList,然後使用代理對象調用
此時的sqlsesion就是sqlSessionTemplate
代理對象為SqlSessionInterceptor,此時調用就是invoke方法
invoke方法調用
*首先擷取sqlSession,然後 裡面大緻的流程就是建立一個DefaultSqlSession對象,并建立一個Executor的對象或者代理對象,比如pageHelper就是代理了此對象Executor
*擷取Executor對象,并檢查是否是需要代理
*執行代理方法
*處理一下事務的邏輯
四,mybatis的執行流程總結
執行流程圖
mapperMethod執行:主要是請求參數的解析
excutor:主要是指StatementHandler的建立,包含 BoundSql 的建立、ParameterHandler和 ResultSetHandler 的建立。
statementHandler 執行:主要執行sql 并對結果集進行處理
參數組裝是在excutor建立之前,攔截器是在建立excutor的時候,是以前期就是參數組裝,BoundSql建立 是在StatementHandler建立的時候,在ParameterHandler和 ResultSetHandler 之前。