本章需要参考之前的两篇博客:
从之前springboot自动装配原理,在资源目录下应该存在META-INF/spring.factories
文件,查看mybatis-spring-boot-autoconfigure
模块,其下该文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
其中,MybatisLanguageDriverAutoConfiguration
内容如下:
// MybatisLanguageDriverAutoConfiguration.java
@Configuration
@ConditionalOnClass(LanguageDriver.class)
public class MybatisLanguageDriverAutoConfiguration {
private static final String CONFIGURATION_PROPERTY_PREFIX = "mybatis.scripting-language-driver";
/**
* Configuration class for mybatis-freemarker 1.1.x or under.
*/
@Configuration
@ConditionalOnClass(FreeMarkerLanguageDriver.class)
@ConditionalOnMissingClass("org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig")
public static class LegacyFreeMarkerConfiguration {
@Bean
@ConditionalOnMissingBean
FreeMarkerLanguageDriver freeMarkerLanguageDriver() {
return new FreeMarkerLanguageDriver();
}
}
/**
* Configuration class for mybatis-freemarker 1.2.x or above.
*/
@Configuration
@ConditionalOnClass({
FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class })
public static class FreeMarkerConfiguration {
@Bean
@ConditionalOnMissingBean
FreeMarkerLanguageDriver freeMarkerLanguageDriver(FreeMarkerLanguageDriverConfig config) {
return new FreeMarkerLanguageDriver(config);
}
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".freemarker")
public FreeMarkerLanguageDriverConfig freeMarkerLanguageDriverConfig() {
return FreeMarkerLanguageDriverConfig.newInstance();
}
}
/**
* Configuration class for mybatis-velocity 2.0 or under.
*/
@Configuration
@ConditionalOnClass(org.mybatis.scripting.velocity.Driver.class)
@ConditionalOnMissingClass("org.mybatis.scripting.velocity.VelocityLanguageDriverConfig")
@SuppressWarnings("deprecation")
public static class LegacyVelocityConfiguration {
@Bean
@ConditionalOnMissingBean
org.mybatis.scripting.velocity.Driver velocityLanguageDriver() {
return new org.mybatis.scripting.velocity.Driver();
}
}
/**
* Configuration class for mybatis-velocity 2.1.x or above.
*/
@Configuration
@ConditionalOnClass({
VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class })
public static class VelocityConfiguration {
@Bean
@ConditionalOnMissingBean
VelocityLanguageDriver velocityLanguageDriver(VelocityLanguageDriverConfig config) {
return new VelocityLanguageDriver(config);
}
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".velocity")
public VelocityLanguageDriverConfig velocityLanguageDriverConfig() {
return VelocityLanguageDriverConfig.newInstance();
}
}
@Configuration
@ConditionalOnClass(ThymeleafLanguageDriver.class)
public static class ThymeleafConfiguration {
@Bean
@ConditionalOnMissingBean
ThymeleafLanguageDriver thymeleafLanguageDriver(ThymeleafLanguageDriverConfig config) {
return new ThymeleafLanguageDriver(config);
}
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf")
public ThymeleafLanguageDriverConfig thymeleafLanguageDriverConfig() {
return ThymeleafLanguageDriverConfig.newInstance();
}
}
可以看到,这个类主要就是注入一个LanguageDriver
实现,主要逻辑在MybatisAutoConfiguration
:
// MybatisAutoConfiguration.java
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({
SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({
DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
...
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
....
}
@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);
}
}
@org.springframework.context.annotation.Configuration
@Import(AutoConfiguredMapperScannerRegistrar.class)
@ConditionalOnMissingBean({
MapperFactoryBean.class, MapperScannerConfigurer.class })
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() {
logger.debug(
"Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
}
}
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (!AutoConfigurationPackages.has(this.beanFactory)) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
return;
}
logger.debug("Searching for mappers annotated with @Mapper");
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
packages.forEach(pkg -> 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);
Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName)
.collect(Collectors.toSet());
if (propertyNames.contains("lazyInitialization")) {
// Need to mybatis-spring 2.0.2+
builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
}
if (propertyNames.contains("defaultScope")) {
// Need to mybatis-spring 2.0.6+
builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
}
registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
下面我们逐一说明。
SqlSessionFactory.class, SqlSessionFactoryBean.class
这两个类,还记得之前分析mybatis和spring整合的,就是通过SqlSessionFactoryBean
,这就表示需要引入mybatis-spring
依赖,而SqlSessionFactory
则是mybatis本身的依赖,即pom需要引入mybatis
和mybatis-spring
这两个依赖MybatisAutoConfiguration
才会起作用SqlSessionFactory
,如果当前IOC容器没有SqlSessionFactory
类型的bean,则这里会创建一个SqlSessionTemplate
,如果当前IOC容器没有SqlSessionTemplate
类型bean,则这里会创建一个MapperFactoryBean.class, MapperScannerConfigurer.class
这两个bean,则会通过:org.springframework.context.annotation.Configuration
@Import(AutoConfiguredMapperScannerRegistrar.class)
@ConditionalOnMissingBean({
MapperFactoryBean.class, MapperScannerConfigurer.class })
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean
通过AutoConfiguredMapperScannerRegistrar
导入,其通过实现registerBeanDefinitions
方法,将MapperScannerConfigurer
这个类注入到了IOC容器中,还记得之前mybatis整合spring的时候怎么用到这个类的吗?这个就是众多的Mapper转成MapperFactory注入到了IOC容器中,至此,借助mybatis-spring,mybatis-springboot将SqlSessionFactoryBean
和众多的Mapper都注入到IOC容器中,大家就可以愉快的使用了。
是不是感觉很简单,其实如果看了前面的两篇,这块理解起来就没什么难度了。