mybatis-spring解析
概述
mybatis-spring让mybatis和Spring无缝对接,无需再关心mybatis中的Configuration、SqlSessionFactory、SqlSession,自动为Mapper创建实例注册到SpringIoc容器中, 并由Spring事务管理。在使用spring的前提下更加简化了Mybatis的操作,使用过程不用关心任何mybatis的相关概念。
Mybatis-spring主要做的内容包含:
-
mybatis相关类 “Spring”化,都注册到Spring 容器中,对mapper额外提供批量扫描功能。
-
事务对接Spring,SqlSession交由Spring事务管理。
我们从使用过程到执行过程分步讲解原理。
一、初始化过程
入口:SqlSessionFactoryBean
使用Mybatis-spring,需要主动配置SqlSessionFactoryBean,所以配置初始化的流程从这里开始。
SqlSessionFactoryBean顾名思义是用于获取SqlSessionFactory,因此其实现了FactoryBean,用于自定义Bean实例化逻辑。
-
FactoryBean,用于自定义Bean实例化逻辑,并注册到Spring容器。SqlSessionFactory是一个很重的类,实例的化的过程比较复杂繁琐。
-
ApplicationListener,监听的是ContextRefreshedEvent事件,配置了快速失败时检查MapperedStatement是否加载完毕。
-
InitializingBean,真正开始实例化的时机,开始构建SqlSessionFactory。
1.1 SqlSessionFactory初始化
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
// 开始构造
this.sqlSessionFactory = buildSqlSessionFactory();
}
构造过程: 至此,
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
XMLConfigBuilder xmlConfigBuilder = null;
// 指定了mybatis-config.xml的路径时
else if (this.configLocation != null) {
// 构造xml解析器
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
}
// 啥都没指定,直接实例化Configuration,使用默认配置
else {
LOGGER.debug(
() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
targetConfiguration = new Configuration();
Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}
// 默认配置设置
Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
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 (!isEmpty(this.typeAliases)) {
Stream.of(this.typeAliases).forEach(typeAlias -> {
targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
});
}
// 插件注册
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> {
targetConfiguration.addInterceptor(plugin);
LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
});
}
// 自定义类型处理器注册
if (hasLength(this.typeHandlersPackage)) {
scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
.filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
.forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}
if (!isEmpty(this.typeHandlers)) {
Stream.of(this.typeHandlers).forEach(typeHandler -> {
targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
});
}
if (!isEmpty(this.scriptingLanguageDrivers)) {
Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
targetConfiguration.getLanguageRegistry().register(languageDriver);
LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
});
}
Optional.ofNullable(this.defaultScriptingLanguageDriver)
.ifPresent(targetConfiguration::setDefaultScriptingLanguage);
if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmls
try {
targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}
Optional.ofNullable(this