網(wǎng)站首頁 編程語言 正文
本文將結合示例代碼、閱讀源碼,去深入了解mybatis與spring boot集成的底層原理。
示例代碼
示例展示最小化配置。
依賴
只記錄相關內(nèi)容:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
application.yml配置
只記錄相關內(nèi)容:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_source_analysis
username: root
password: 123456
druid:
filters: stat
maxActive: 5
initialSize: 5
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 5
# 此處是mybatis自動裝配的最小化配置
# 如果在mapper接口上使用注解方式編寫SQL的話,這個配置也是不需要的
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
mapper xml配置文件
與之前一樣,不記錄。
MybatisConfig配置類
@MapperScan(basePackages = {"org.net5ijy.mybatis.test.mapper"})
@Configuration
public class MybatisConfig {
// 由于DataSource、SqlSessionFactory和SqlSessionTemplate由spring boot mybatis自動裝配,這個類可以空白
}
Mapper接口
與之前一樣,不記錄。
接口層編寫
只記錄相關內(nèi)容:
@RestController
@RequestMapping("/blog")
public class BlogController {
private BlogMapper blogMapper;
public BlogController(BlogMapper blogMapper) {
this.blogMapper = blogMapper;
}
// other code
}
啟動類
@SpringBootApplication
public class MybatisSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisSpringBootApplication.class, args);
}
}
核心原理
我們依賴的mybatis-spring-boot-starter包,而這個包沒有實際代碼和配置文件,只是引入了mybatis、mybatis-spring、和mybatis-spring-boot-autoconfigure等包。
自動裝配的實現(xiàn)在mybatis-spring-boot-autoconfigure包里面。
我們知道spring boot的自動裝配原理是在自動裝配包的META-INF下創(chuàng)建spring.factories文件,在文件里面配置EnableAutoConfiguration的配置類全名即可實現(xiàn)自動裝配,我們看一下mybatis-spring-boot-autoconfigure包的spring.factories文件:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
核心內(nèi)容就在MybatisAutoConfiguration這個類。
所以這個類會幫助我們創(chuàng)建SqlSessionFactory和SqlSessionTemplate,而DataSource是由DataSourceAutoConfiguration類來做的(這個暫不討論)。
所以應該從MybatisAutoConfiguration為入口開始分析。
其實基本上所有的第三方庫的集成都是這樣的原理:
- 一個starter庫
- 一個autoconfigure庫
- 一個spring.factories文件,其實這個才是最重要的。至于是一個包還是兩個包,都問題不大,可以實現(xiàn)就行
- 一個AutoConfiguration類
- 一個Properties類
至于spring.factories文件被加載的原理,這是spring boot的內(nèi)容,本文不做擴展分析。
源碼分析
MybatisAutoConfiguration類
這個類負責創(chuàng)建SqlSessionFactory和SqlSessionTemplate對象。
看一下這個類的成員和構造方法:
public class MybatisAutoConfiguration implements InitializingBean {
private final MybatisProperties properties;
private final Interceptor[] interceptors;
private final TypeHandler[] typeHandlers;
private final LanguageDriver[] languageDrivers;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
private final List<ConfigurationCustomizer> configurationCustomizers;
public MybatisAutoConfiguration(
MybatisProperties properties, // 用戶在application.yml里面的配置參數(shù),后續(xù)詳解
// 容器里面的Interceptor攔截器,就是說使用@Component標注的Interceptor實現(xiàn)類對象都會在這里,
// 這是spring的依賴注入特性,
// 這種機制更便于組件擴展
ObjectProvider<Interceptor[]> interceptorsProvider,
// 容器里面的TypeHandler集合,原理同上
ObjectProvider<TypeHandler[]> typeHandlersProvider,
ObjectProvider<LanguageDriver[]> languageDriversProvider,
ResourceLoader resourceLoader,
ObjectProvider<DatabaseIdProvider> databaseIdProvider,
// 這個也是一種擴展機制,讓用戶獲取到Configuration對象,然后做操作
ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
// 成員變量賦值
}
創(chuàng)建SqlSessionFactory
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 之前與spring集成時做過分析
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
// 設置mybatis.configLocation配置
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
// 這個方法要看一下
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);
}
// mapper xml掃描
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
Set<String> factoryPropertyNames = Stream
.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors())
.map(PropertyDescriptor::getName)
.collect(Collectors.toSet());
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
// Need to mybatis-spring 2.0.2+
factory.setScriptingLanguageDrivers(this.languageDrivers);
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
defaultLanguageDriver = this.languageDrivers[0].getClass();
}
}
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
// Need to mybatis-spring 2.0.2+
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}
// 這個方法之前看過,不再分析
return factory.getObject();
}
private void applyConfiguration(SqlSessionFactoryBean factory) {
Configuration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new Configuration();
}
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
// 這里在調(diào)用用戶的ConfigurationCustomizer自定義擴展邏輯
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
factory.setConfiguration(configuration);
}
創(chuàng)建SqlSessionTemplate
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
代碼比較簡單,就是創(chuàng)建SqlSessionTemplate對象。
MybatisProperties配置類
MybatisProperties配置類封裝了用戶的所有mybatis配置,這個類讀取mybatis.開始的配置參數(shù),封裝到自己的屬性中。
類定義:
@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties {
// ...
}
支持的配置:
從圖中可以看到,這類本身支持的配置并不是很多:
mapperLocations - mapper xml配置文件位置
checkConfigLocation - 是否對主配置文件進行檢查,默認false不檢查
configLocation - 主配置文件位置
configurationProperties - 主配置擴展屬性
defaultScriptingLanguageDriver - 默認的腳本語言模板類
executorType - SqlSessionTemplate的運行模式
typeAliases* - 類型別名
typeHandlersPackage - 類型處理器
其余的以mybatis.configuration.開始的配置封裝在MybatisProperties的Configuration對象中,這個對象封裝mybatis的核心配置,屬性較多。
以mybatis.scripting-language-driver.開始的配置是腳本語言模板類的屬性,本文不介紹。
@MapperScan注解原理(略)
在 mybatis源碼分析_集成spring源碼分析 文中有詳細分析,此處略。
插件加載原理
三種方式
- 使用@Component標注Interceptor實現(xiàn)類
- 使用ConfigurationCustomizer的customize方法向Configuration addInterceptor
- 編寫mybatis主配置文件,使用plugins標簽注冊
@Component標注Interceptor實現(xiàn)類
在之前分析MybatisAutoConfiguration時看過構造方法,其中讓spring注入了一個ObjectProvider<Interceptor[]>對象,這個對象里面是容器里面所有的Interceptor接口的實例對象。
ObjectProvider接口是spring 4.3提供的新特性,是ObjectFactory接口的擴展,專門為注入點設計的,可以讓注入變得更加寬松和更具有可選項。
如果待注入?yún)?shù)的bean為空或有多個時,ObjectProvider就會起作用:
- 如果注入實例為空時,使用ObjectProvider則避免了強依賴導致的依賴對象不存在異常
- 如果有多個實例,ObjectProvider的方法會根據(jù)bean實現(xiàn)的Ordered接口或@Order注解指定的先后順序獲取一個Bean。從而了提供了一個更加寬松的依賴注入方式
所以就可以理解這種方法了。
所以不只是使用@Component標注Interceptor實現(xiàn)類,在Configuration配置類中使用@Bean創(chuàng)建bean方式也是可行的。
@Bean
public PrintSqlInterceptor printSqlInterceptor() {
return new PrintSqlInterceptor();
}
ConfigurationCustomizer的customize方法
MybatisAutoConfiguration的構造方法還注入了ObjectProvider<List<ConfigurationCustomizer>>對象,其原理和前文一樣,我們需要了解的是ConfigurationCustomizer接口:
@FunctionalInterface
public interface ConfigurationCustomizer {
void customize(Configuration configuration);
}
這是一個函數(shù)接口,customize方法接收一個mybatis的Configuration對象作為參數(shù),可以使用Configuration的addInterceptor(Interceptor)方法注冊插件。
其實不止是插件,其他操作Configuration對象的需求也可以使用這個接口來實現(xiàn)。
原文鏈接:https://blog.csdn.net/xuguofeng2016/article/details/125919307
相關推薦
- 2022-06-30 卷積神經(jīng)網(wǎng)絡經(jīng)典模型及其改進點學習匯總_python
- 2021-10-13 linux環(huán)境下恢復rm誤刪的文件方法_Linux
- 2023-03-16 python使用redis實現(xiàn)消息隊列(異步)的實現(xiàn)完整例程_python
- 2022-06-02 關于Python使用turtle庫畫任意圖的問題_python
- 2022-06-25 Python+PuLP實現(xiàn)線性規(guī)劃的求解_python
- 2022-06-09 ASP.NET?Core記錄日志_實用技巧
- 2023-08-13 fastadmin框架中如何添加一個自定義按鈕
- 2022-11-27 C語言三種函數(shù)調(diào)用約定_cdecl與_stdcall及_fastcall詳細講解_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支