<>在springboot项目中使用mybatis只需要引入mybatis-spring-boot-starter即可使用,从源码的角度分析其自动装配原理
<>1.引入依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>
mybatis-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency>
<>2.导入mybatis与mybatis-spring依赖
1.在maven库中找到mybatis-spring-boot-autoconfigure=》MATA-INF-spring.factories文件,文件
# springboot会扫描spring.factories文件中EnableAutoConfiguration指定类 #注入到IOC容器中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
a)第一个类MybatisLanguageDriverAutoConfiguration,当存在LanguageDriver时生效
b)MybatisAutoConfiguration,此类为springboot整合mybatis核心类
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by
Fernflower decompiler) // package org.mybatis.spring.boot.autoconfigure; import
java.beans.FeatureDescriptor; import java.util.Iterator; import java.util.List;
import java.util.Set; import java.util.stream.Collectors; import java.util.
stream.Stream; import javax.sql.DataSource; import org.apache.ibatis.annotations
.Mapper; import org.apache.ibatis.mapping.DatabaseIdProvider; import org.apache.
ibatis.plugin.Interceptor; import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.
SqlSessionFactory; import org.apache.ibatis.type.TypeHandler; import org.mybatis
.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperFactoryBean; import org.mybatis.spring.
mapper.MapperScannerConfigurer; import org.slf4j.Logger; import org.slf4j.
LoggerFactory; import org.springframework.beans.BeanWrapper; import org.
springframework.beans.BeanWrapperImpl; import org.springframework.beans.factory.
BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import
org.springframework.beans.factory.InitializingBean; import org.springframework.
beans.factory.ObjectProvider; import org.springframework.beans.factory.support.
BeanDefinitionBuilder; import org.springframework.beans.factory.support.
BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.
AutoConfigurationPackages; import org.springframework.boot.autoconfigure.
AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.
ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.
ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.
condition.ConditionalOnSingleCandidate; import org.springframework.boot.
autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.
context.properties.EnableConfigurationProperties; import org.springframework.
context.annotation.Bean; import org.springframework.context.annotation.
Configuration; import org.springframework.context.annotation.Import; import org.
springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.
springframework.core.io.Resource; import org.springframework.core.io.
ResourceLoader; import org.springframework.core.type.AnnotationMetadata; import
org.springframework.util.Assert; import org.springframework.util.CollectionUtils
; import org.springframework.util.ObjectUtils; import org.springframework.util.
StringUtils; //指定配置类 @Configuration
//当存在SqlSessionFactory.class,SqlSessionFactoryBean.class时生效 @ConditionalOnClass(
{SqlSessionFactory.class, SqlSessionFactoryBean.class})
//当只有一个单例的DataSource或者指定了首选DataSource时生效 @ConditionalOnSingleCandidate(
DataSource.class) //启用Mybatis属性配置 @EnableConfigurationProperties({
MybatisProperties.class})
//在DataSourceAutoConfiguration,MybatisLanguageDriverAutoConfiguration配置完后才咸亨小
@AutoConfigureAfter({DataSourceAutoConfiguration.class,
MybatisLanguageDriverAutoConfiguration.class}) public class
MybatisAutoConfiguration implements InitializingBean { private static final
Logger logger= LoggerFactory.getLogger(MybatisAutoConfiguration.class); 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, ObjectProvider<
Interceptor[]> interceptorsProvider, ObjectProvider<TypeHandler[]>
typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider,
ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider>
databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>>
configurationCustomizersProvider) { this.properties = properties; this.
interceptors= (Interceptor[])interceptorsProvider.getIfAvailable(); this.
typeHandlers= (TypeHandler[])typeHandlersProvider.getIfAvailable(); this.
languageDrivers= (LanguageDriver[])languageDriversProvider.getIfAvailable();
this.resourceLoader = resourceLoader; this.databaseIdProvider = (
DatabaseIdProvider)databaseIdProvider.getIfAvailable(); this.
configurationCustomizers= (List)configurationCustomizersProvider.getIfAvailable(
); } public void afterPropertiesSet() { this.checkConfigFileExists(); } private
void checkConfigFileExists() { if (this.properties.isCheckConfigLocation() &&
StringUtils.hasText(this.properties.getConfigLocation())) { Resource resource =
this.resourceLoader.getResource(this.properties.getConfigLocation()); Assert.
state(resource.exists(), "Cannot find config location: " + resource + " (please
add config file or check your Mybatis configuration)"); } }
//当IOC容器中没有sqlSessionFactory时创建bean实例 @Bean @ConditionalOnMissingBean public
SqlSessionFactorysqlSessionFactory(DataSource dataSource) throws Exception {
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); } return factory.
getObject(); } private void applyConfiguration(SqlSessionFactoryBean factory) {
org.apache.ibatis.session.Configuration configuration = this.properties.
getConfiguration(); if (configuration == null && !StringUtils.hasText(this.
properties.getConfigLocation())) { configuration = new org.apache.ibatis.session
.Configuration(); } if (configuration != null && !CollectionUtils.isEmpty(this.
configurationCustomizers)) { Iterator var3 = this.configurationCustomizers.
iterator(); while(var3.hasNext()) { ConfigurationCustomizer customizer = (
ConfigurationCustomizer)var3.next(); customizer.customize(configuration); } }
factory.setConfiguration(configuration); }
//当IOC容器中没有sqlSessionTemplate创建实例化bean @Bean @ConditionalOnMissingBean public
SqlSessionTemplatesqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType= this.properties.getExecutorType(); return
executorType!= null ? new SqlSessionTemplate(sqlSessionFactory, executorType) :
new SqlSessionTemplate(sqlSessionFactory); }
//配置文件引入MybatisAutoConfiguration与AutoConfiguredMapperScannerRegistrar
//当容器中没有MapperFactoryBean.class, MapperScannerConfigurer.class @Configuration
@Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.
class}) public static class MapperScannerRegistrarNotFoundConfiguration
implements InitializingBean { public MapperScannerRegistrarNotFoundConfiguration
() { } public void afterPropertiesSet() { MybatisAutoConfiguration.logger.debug(
"Not found configuration for registering mapper bean using @MapperScan,
MapperFactoryBean and MapperScannerConfigurer."); } } public static class
AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware,
ImportBeanDefinitionRegistrar{ private BeanFactory beanFactory; public
AutoConfiguredMapperScannerRegistrar() { } public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if
(!AutoConfigurationPackages.has(this.beanFactory)) { MybatisAutoConfiguration.
logger.debug("Could not determine auto-configuration package, automatic mapper
scanning disabled."); } else { MybatisAutoConfiguration.logger.debug("Searching
for mappers annotated with @Mapper"); List<String> packages =
AutoConfigurationPackages.get(this.beanFactory); if (MybatisAutoConfiguration.
logger.isDebugEnabled()) { packages.forEach((pkg) -> { MybatisAutoConfiguration.
logger.debug("Using auto-configuration base package '{}'", pkg); }); }
BeanDefinitionBuilder builder= BeanDefinitionBuilder.genericBeanDefinition(
MapperScannerConfigurer.class); builder.addPropertyValue(
"processPropertyPlaceHolders", true); builder.addPropertyValue("annotationClass"
, Mapper.class); builder.addPropertyValue("basePackage", StringUtils.
collectionToCommaDelimitedString(packages)); BeanWrapper beanWrapper = new
BeanWrapperImpl(MapperScannerConfigurer.class); Stream.of(beanWrapper.
getPropertyDescriptors()).filter((x) -> { return x.getName().equals(
"lazyInitialization"); }).findAny().ifPresent((x) -> { builder.addPropertyValue(
"lazyInitialization", "${mybatis.lazy-initialization:false}"); }); registry.
registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.
getBeanDefinition()); } } public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory; } } }
从源码中可以看出,当有SqlSessionFactory.class,SqlSessionFactoryBean.class这个两个类存在,并且指定了DataSource之后,该配置类即可生效,生效时IOC容器中若不存在,则会创建sqlSessionFactory与sqlSessionTemplate实例化bean,若在其他地方应用,则直接注入即可,在注入sqlSessionFactory是需要注入DataSource,DataSource到底从哪里来呢?springboot-autoconfigure-jdbc中有一配置类,该配置类会自动注DataSource
在MybatisAutoConfiguration
有一个这样的配置文件,当容器中缺失这个几个bean时该配置类生效,再次注入MybatisAutoConfiguration
实例,其实在正常情况下是不生效,那个这个到底是什么时候生效的呢?在启动的时候,需要加入一个注解@MapperScan(""),包扫描路径,该注解会向IOC注册MapperScannerRegistrar
//配置文件引入MybatisAutoConfiguration与AutoConfiguredMapperScannerRegistrar
//当容器中没有MapperFactoryBean.class, MapperScannerConfigurer.class @Configuration
@Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.
class}) public static class MapperScannerRegistrarNotFoundConfiguration
implements InitializingBean { public MapperScannerRegistrarNotFoundConfiguration
() { } public void afterPropertiesSet() { MybatisAutoConfiguration.logger.debug(
"Not found configuration for registering mapper bean using @MapperScan,
MapperFactoryBean and MapperScannerConfigurer."); } }
@MapperScan会引入MapperScannerRegistrar
springboot自动装配流程
1.mybatis-spring-boot-autoconfigure-2.1.2.jar=》spring.factories文件中扫描
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
2.完成MybatisAutoConfiguration配置文件中bean实例化,在IOC容器中创建SqlSessionFactory与SqlSessionTemplate实例