MyBaits自動(dòng)配置原理
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
作者 | 歪頭兒在帝都
來源 | urlify.cn/j2MfQj
前言
首先我們建立一個(gè)SpringBoot工程,導(dǎo)入mybatis-spring-boot-starter依賴。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
導(dǎo)入后發(fā)現(xiàn)這個(gè)依賴其實(shí)就是幫助我們導(dǎo)入了mybatis需要的依賴,其中和自動(dòng)配置相關(guān)最重要的一個(gè)就是mybatis-spring-boot-autoconfigure
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
</dependencies>
MyBatis自動(dòng)配置中是如何工作的
如上面分析自動(dòng)配置的關(guā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
從spring.factories文件看到這里通過SPI機(jī)制加載了兩個(gè)類
MybatisAutoConfiguration
MybatisLanguateDriverAutoConfiguration.
MybatisAutoConfiguration

//表示這是一個(gè)Spring配置類
@Configuration
//這個(gè)類需要在classpath中存在SqlSessionFactory和SqlSessionFactoryBean時(shí)才生效
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) --
//這個(gè)類需要有一個(gè)DataSource的Canidate注冊(cè)到Spring容器中
@ConditionalOnSingleCandidate(DataSource.class)
//使MybatisProperties注解類生效
@EnableConfigurationProperties({MybatisProperties.class})
//需要在DataSourceAutoConfiguration和MybatisLanguageDriverAutoConfiguration自動(dòng)配置之后執(zhí)行
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
}
MybatisAutoConfiguration#sqlSessionFactory
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
//創(chuàng)建一個(gè)SqlSessionFactoryBean, 在mybatis-spring項(xiàng)目下
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()));
}
//應(yīng)用Configuration對(duì)象
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();
}
}
//設(shè)置默認(rèn)的語言驅(qū)動(dòng)類
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}
//這里默認(rèn)會(huì)返回一個(gè)DefaultSqlSessionFactory對(duì)象
return factory.getObject();
}
MybatisAutoConfiguration#sqlSessionTemplate
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
}
到這里也就知道了MyBatis自動(dòng)配置其實(shí)就是替我們完成了SqlSessionFactory和SqlSessionTempate的創(chuàng)建, 省去了自己導(dǎo)入相關(guān)依賴和配置相關(guān)Bean的麻煩.
MybatisLanguageDriverAutoConfiguration
這個(gè)類的配置是對(duì)各個(gè)語言的支持,比如Thymeleaf, Velocity,LegacyVelociy, FreeMarker等視圖組件的支持。
@Configuration
@ConditionalOnClass({LanguageDriver.class})
public class MybatisLanguageDriverAutoConfiguration {
private static final String CONFIGURATION_PROPERTY_PREFIX = "mybatis.scripting-language-driver";
public MybatisLanguageDriverAutoConfiguration() {
}
@Configuration
@ConditionalOnClass({ThymeleafLanguageDriver.class})
public static class ThymeleafConfiguration {
public ThymeleafConfiguration() {
}
}
@Configuration
@ConditionalOnClass({VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class})
public static class VelocityConfiguration {
public VelocityConfiguration() {
}
}
@Configuration
@ConditionalOnClass({Driver.class})
@ConditionalOnMissingClass({"org.mybatis.scripting.velocity.VelocityLanguageDriverConfig"})
public static class LegacyVelocityConfiguration {
public LegacyVelocityConfiguration() {
}
}
@Configuration
@ConditionalOnClass({FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class})
public static class FreeMarkerConfiguration {
public FreeMarkerConfiguration() {
}
}
@Configuration
@ConditionalOnClass({FreeMarkerLanguageDriver.class})
@ConditionalOnMissingClass({"org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig"})
public static class LegacyFreeMarkerConfiguration {
public LegacyFreeMarkerConfiguration() {
}
}
}
MybatisLanguageDriverAutoConfiguration類在org.mybatis.spring.boot.autoconfigure包下,我刪掉了內(nèi)部靜態(tài)類下的代碼,為了保持這個(gè)類看起來更直觀
自定義Mapper是如何被掃描的
業(yè)務(wù)開發(fā)中,我們是聲明接口(Mapper),那么我們自定義的Mapper是如何被掃描的呢, 我們繼續(xù)順著MybatisAutoConfiguration代碼分析,其內(nèi)部包含了一個(gè)AutoConfiguredMapperScannerRegistrar的內(nèi)部靜態(tài)類.
AutoConfiguredMapperScannerRegistrar
registerBeanDefinitions
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
public AutoConfiguredMapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (!AutoConfigurationPackages.has(this.beanFactory)) {
} else {
//1.獲取到SpringBoot的基礎(chǔ)包路徑
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
//2.生成一個(gè)BeanDefinition的構(gòu)造器,用于構(gòu)建MapperScannerConfigurer的 //BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
//3.設(shè)置@Mapper注解的接口才會(huì)被當(dāng)成Mapper接口
builder.addPropertyValue("annotationClass", Mapper.class);
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
//4.獲取MapperScannerConfigurer的屬性名稱
Set<String> propertyNames = (Set)Stream.of(beanWrapper.getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
if (propertyNames.contains("lazyInitialization")) {
builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
}
if (propertyNames.contains("defaultScope")) {
builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
}
//5.這里添加一個(gè)MapperScannerConfigurer的BeanDefinition對(duì)象,也就是注入一個(gè)
//MapperScannerConfigurer對(duì)象
registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
}
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
AutoConfiguredMapperScannerRegistrar類是MybatisAutoConfiguration的內(nèi)部靜態(tài)類,位于包org.mybatis.spring.boot.autoconfigure下。
可以看到這個(gè)類實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar接口是Spring用來動(dòng)態(tài)注冊(cè)Bean的,也就是會(huì)向Spring容器中注入一個(gè)BeanDefinition, 這個(gè)BeanDefinition就是MapperScannerConfigurer。
ImportBeanDefinitionRegistrar實(shí)現(xiàn)類只能通過其他類@Import的方式來加載,通常是配置類或者啟動(dòng)類,所以MybatisAutoConfiguration類下還有一個(gè)內(nèi)部類MapperScannerRegistrarNotFoundConfiguration如下。
@Configuration
@Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
}這個(gè)方法里最后會(huì)調(diào)用接口BeanDefinitionRegistry.registerBeanDefinition, beanName是"org.mybatis.spring.mapper.MapperScannerConfigurer", registerBeanDefinition方法實(shí)際會(huì)調(diào)用DefaultListableBeanFactory.registerBeanDefinition。DefaultListableBeanFactory是BeanDefinitionRegistry接口的實(shí)現(xiàn)類。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory,
BeanDefinitionRegistry,
Serializable {
}
AutoConfiguredMapperScannerRegistrar類和MapperScanner注解的作用是一樣的,如果你沒有通過以下三種配置方式掃描Mapper接口的包路徑
配置MapperScannerConfigurer掃描器類型的Spring Bean
@Mapper注解
<mybatis: scan/>標(biāo)簽
那么這里就會(huì)通過AutoConfiguredMapperScannerRegistrar類添加一個(gè)MapperScannerConfigurer掃描器對(duì)象,去掃描SpringBoot包設(shè)置的基礎(chǔ)包路徑,也就是啟動(dòng)類的同級(jí)目錄。如果設(shè)置了@Mapper注解,則會(huì)當(dāng)成Mapper接口解析,那么這里自動(dòng)配置則不生效。
MapperScannerConfigurer
MapperScannerConfigurer
MapperScannerConfigurer實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor 接口又繼承了BeanFactoryPostProcessor接口, 也就是說在MapperScannerConfigurer類里需要實(shí)現(xiàn)這兩個(gè)接口的方法。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
在MapperScannerConfigurer類里可以看到這里只實(shí)現(xiàn)了postProcessBeanDefinitionRegistry。
BeanDefinitionRegistryPostProcessor
Spring里有兩個(gè)用來動(dòng)態(tài)注冊(cè)Bean到容器中(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar)。ImportBeanDefinitionRegistrar上文中有提到。
BeanDefinitionRegistryPostProcessor接口實(shí)現(xiàn)了BeanFactoryPostProcessor接口,是Spring框架的BeanDefinitionRegistry的后置處理器,用來注冊(cè)額外的BeanDefinition,postProcessBeanDefinitionRegistry方法會(huì)在所有的beanDefinition被加載了,但是所有的Bean還沒創(chuàng)建前調(diào)用。BeanDefinitionRegistryPostProcessor經(jīng)常被用來注冊(cè)BeanFactoryPostProcessor的BeanDefinition。
postProcessBeanDefinitionRegistry
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
this.processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(this.lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
}
if (StringUtils.hasText(this.defaultScope)) {
scanner.setDefaultScope(this.defaultScope);
}
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}
}
MapperScannerConfigurer在包org.mybatis.spring.mapper下.
這里會(huì)調(diào)用ClassPathMapperScanner.scan(),而ClassPathMapperScanner又繼承了ClassPathBeanDefinitionScanner,所以這里scan()會(huì)調(diào)用ClassPathBeanDefinitionScanner.scan(), 而ClassPathBeanDefinitionScanner.scan() 第二句代碼又調(diào)用了this.doScan(basePackages), this.doScan()又調(diào)用了ClassPathMapperScanner.doScan(), 而這個(gè)方法第一句代碼又調(diào)用了super.doScan(basePackages),父子類來回互相調(diào)用,有點(diǎn)暈頭轉(zhuǎn)向的。
org.mybatis.spring.mapper.ClassPathMapperScanner
org.springframework.context.annotation.ClassPathBeanDefinitionScanner這個(gè)類在spring-context.jar
ClassPathMapperScanner
ClassPathBeanDefinitionScanner#scan
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
this.doScan(basePackages);
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}
ClassPathMapperScanner#doScan()
這個(gè)方法里在mybatis自動(dòng)配置算比較重要的一個(gè)方法,也就是幫助我們自動(dòng)配置MapperFactoryBean, 會(huì)把根據(jù)basePackage注冊(cè)進(jìn)Spring容器的BeanDefinition的beanClass設(shè)置成MapperFactoryBean。
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> {
return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
});
} else {
//這是一個(gè)關(guān)鍵方法,會(huì)處理已經(jīng)注冊(cè)進(jìn)Spring容器的beanDefinition,也就是會(huì)把
//已經(jīng)注冊(cè)進(jìn)Spring容器的beanDefinitiond的beanClass為MapperFactoryBean
this.processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
ClassPathBeanDefinitionScanner#doScan()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
String[] var3 = basePackages;
int var4 = basePackages.length;
for(int var5 = 0; var5 < var4; ++var5) {
String basePackage = var3[var5];
//這個(gè)方法會(huì)掃描指定basePackage下被@Mapper注解標(biāo)注的接口
Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
Iterator var8 = candidates.iterator();
while(var8.hasNext()) {
BeanDefinition candidate = (BeanDefinition)var8.next();
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//這里獲取beanName, 默認(rèn)值是類名首字母小寫
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
}
//檢查對(duì)應(yīng)的Mapper接口是否被注冊(cè)進(jìn)Spring容器中。
if (this.checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
this.registerBeanDefinition(definitionHolder, this.registry);
}
}
}
//這個(gè)集合返回以后 Spring容器會(huì)將里面的所有內(nèi)容注冊(cè)到容器中
return beanDefinitions;
}
ClassPathMapperScanner#processBeanDefinitions
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
BeanDefinitionRegistry registry = this.getRegistry();
Iterator var4 = beanDefinitions.iterator();
while(var4.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var4.next();
AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition();
boolean scopedProxy = false;
if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> {
return new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]");
});
scopedProxy = true;
}
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> {
return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
});
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
//1.這里把普通接口設(shè)置成MapperFactoryBean
definition.setBeanClass(this.mapperFactoryBeanClass);
//2.是否把Mapper接口加入到Mybatis的Config當(dāng)中去, 這里設(shè)置為true
definition.getPropertyValues().add("addToConfig", this.addToConfig);
definition.setAttribute("factoryBeanObjectType", beanClassName);
boolean explicitFactoryUsed = false;
//2.從核心容器里獲取SqlSessionFactory賦值給MapperFactoryBean
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
//3.從核心容器里獲取SqlSessionTemplate賦值給MapperFactoryBean
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> {
return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
});
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> {
return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
});
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
LOGGER.debug(() -> {
return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.";
});
definition.setAutowireMode(2);
}
definition.setLazyInit(this.lazyInitialization);
if (!scopedProxy) {
if ("singleton".equals(definition.getScope()) && this.defaultScope != null) {
definition.setScope(this.defaultScope);
}
if (!definition.isSingleton()) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
registry.removeBeanDefinition(proxyHolder.getBeanName());
}
registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
}
}
}
}

再看spring.factories文件
上面只是完成了MyBatis 自動(dòng)配置的工作,那么這些自動(dòng)配置是如何在SpringBoot啟動(dòng)時(shí)執(zhí)行呢?還記得SpringBoot的EnableAutoConfiguration注解吧,它是利用SpringFactoriesLoader機(jī)制加載所有的AutoConfiguration類,所以我們需要把編寫好的自動(dòng)配置類放在META-INF/spring.factories文件中,這也就是我們一開始分析的mybatis-spring-boot-starter-autoconfigure的文件結(jié)構(gòu)的原因。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
總結(jié)
mybatis-spring-boot-starter將mybatis需要的依賴全部引入。
starter通過SPI機(jī)制引入了一個(gè)配置的Class(MyBatisAutoConfiguration)。它負(fù)責(zé)注冊(cè)SqlSessionFactory和SqlSessionTemplate到Spring容器中,使用MyBatis開發(fā)時(shí)絕大部分功能要使用這兩個(gè)類來完成。
注入了AutoConfiguredMapperScannerRegistrar這個(gè)Bean到Spring容器,它負(fù)責(zé)將MapperScanner引入到Spring容器,然后MapperScanner會(huì)將工程中指定package下的Mapper轉(zhuǎn)化為BeanDefinition并且注冊(cè)到Spring容器中。
在開發(fā)中使用某個(gè)具體的Mapper時(shí),Spring能夠從容器中找到這個(gè)Mapper對(duì)應(yīng)的BeanDefinition,將其實(shí)例化并且注入,這樣開發(fā)者就可以使用了。
SpringBoot+MyBatis自動(dòng)配置涉及到Spring中兩個(gè)自動(dòng)注冊(cè)Bean的關(guān)鍵接口(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar),也是我們業(yè)務(wù)開發(fā)中需要重點(diǎn)關(guān)注的地方。
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長(zhǎng)按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 

