自动配置无非涉及几个方面
- mapper的代理注册
- sql语句的注册
查看自动配置类
路径 :D:\maven-repository\com\baomidou\mybatis-plus-boot-starter\3.4.1\mybatis-plus-boot-starter-3.4.1.jar!\META-INF\spring.factories
代码解释
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {
// 省略其他字段...
// 检查配置文件是否存在
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)");
}
}
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 创建 MybatisSqlSessionFactoryBean 实例,设置数据源
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
// 省略配置和设置其他属性...
// 返回 SqlSessionFactory 实例
return factory.getObject();
}
// 检查 Spring 容器中的 bean,并进行消费
private <T> void getBeanThen(Class<T> clazz, Consumer<T> consumer) {
if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
consumer.accept(this.applicationContext.getBean(clazz));
}
}
// 应用 Mybatis 配置
private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {
MybatisConfiguration configuration = this.properties.getConfiguration();
// 省略其他配置...
factory.setConfiguration(configuration);
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
// 根据属性返回 SqlSessionTemplate 实例
ExecutorType executorType = this.properties.getExecutorType();
return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
}
// 省略其他内部类和方法...
}
这个类做了几件事
- 注册SqlSessionFactory 这个类主要是为SqlSessionTemplate提供会话获取工厂 当然了 mybatisplus 进一步封装为了SqlSessionTemplate 为了和spring的事务结合
- 注册SqlSessionTemplate
- 注册AutoConfiguredMapperScannerRegistrar
我们看看mapper是怎么注册到spring容器里面的
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);
Stream.of(beanWrapper.getPropertyDescriptors())
// Need to mybatis-spring 2.0.2+
.filter(x -> x.getName().equals("lazyInitialization")).findAny()
.ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}"));
registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
可以看到这个类注册了一个BeanDefinition叫MapperScannerConfigurer,再进去看看
可以看到 里面进一步使用ClassPathMapperScanner来扫描所有的 this.annotationClass类 而上面配置MapperScannerConfigurer的时候是扫描这个注解
其中ClassPathMapperScanner重写了doScan方法
点进去processBeanDefinitions(beanDefinitions)看看
可以看到将扫描的mapper包装为
definition.setBeanClass(this.mapperFactoryBeanClass);
这个类最后会注册一个mapper代理
我们进一步进去configuration.addMapper(this.mapperInterface); 看看怎么注册的
这里进一步的将new MapperProxyFactory<>(type)注册到knownMappers中,我们点进去看看
可以看到 最后是封装为一个MybatisMapperProxy对象
好了 mapper怎么注册到spring的流程通了
sql 语句什么时候注册进去的呢?
我们注意到 注册mapper的时候下面还有两行语句
这里就是注册sql语句的地方,我们点进去看看
其中有一句loadXmlResource();
我们点进去看看
可以看到这里就是加载xml的地方String xmlResource = type.getName().replace('.', '/') + ".xml"; 这一句就是为什么xml要和mapper放在一个文件夹的关键了,直接是吧后缀替换为xml再去读取
这里就是加载一些配置和一些sql语句了,接着就是注册mybatisplus自带的增删改查了