0. 前言:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud?characterEncoding=utf8&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
username: root
password: 123456
mybatis:
# mybatis-config.xml 配置文件的路径 与 configuration 不可一起设置
#config-location: classpath:mapper/mybatis-config.xml
# sql映射文件的位置
mapper-locations: classpath:mapper/*.xml
# 开启驼峰命名转化
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启别名
type-aliases-package: com.example.demo.easy.domain
1. 自动配置类MybatisAutoConfiguration:
1.1. SqlSessionFactory的生成:
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(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()));
}
// ... ... 省略一些赋值,详细可看源码
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
return factory.getObject();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configuration != null) {
... ...
} else if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
... ...
}
// ... ... yml的配置项赋值targetConfiguration
if (hasLength(this.typeAliasesPackage)) {
scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
.filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
.filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}
... ...
if (xmlConfigBuilder != null) {
try {
// 解析mybatis-config.xml配置项并会覆盖yml的配置
xmlConfigBuilder.parse();
LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}
... ...
if (this.mapperLocations != null) {
... ...
try {
// mapper.xml会被解析封装成MappedStatement对象(用于存储要映射的SQL语句的id、参数等信息)
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse();
}
... ...
}
}
} else {
LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
}
// 创建DefaultSqlSessionFactory
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
1.2. Mapper的扫描和代理生成:
@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.");
}
}
1.2.1. MapperScannerConfigurer
1.2.2. MapperFactoryBean
1.2.3. getMapper生成代理对象