在MyBatis篇内容的最后我们来给大家详细介绍下Spring是如何整合MyBatis的。让大家彻底掌握MyBatis的底层设计原理及实现。
MyBatis整合Spring原理
把MyBatis集成到Spring里面,是为了进一步简化MyBatis的使用,所以只是对MyBatis做了一些封装,并没有替换MyBatis的核心对象。也就是说:MyBatis jar包中的SqlSessionFactory、SqlSession、MapperProxy这些类都会用到。mybatis-spring.jar里面的类只是做了一些包装或者桥梁的工作。
只要我们弄明白了这三个对象是怎么创建的,也就理解了Spring继承MyBatis的原理。我们把它分成三步:
- SqlSessionFactory在哪创建的。
- SqlSession在哪创建的。
- 代理类在哪创建的。
1 SqlSessionFactory
首先我们来看下在MyBatis整合Spring中SqlSessionFactory的创建过程,查看这步的入口在Spring的配置文件中配置整合的标签中
我们进入SqlSessionFactoryBean中查看源码发现,其实现了InitializingBean 、FactoryBean、ApplicationListener 三个接口
接口 | 方法 | 作用 |
---|---|---|
FactoryBean | getObject() | 返回由FactoryBean创建的Bean实例 |
InitializingBean | afterPropertiesSet() | bean属性初始化完成后添加操作 |
ApplicationListener | onApplicationEvent() | 对应用的时间进行监听 |
1.1 afterPropertiesSet
我们首先来看下 afterPropertiesSet 方法中的逻辑
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
可以发现在afterPropertiesSet中直接调用了buildSqlSessionFactory方法来实现 sqlSessionFactory 对象的创建
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
// 解析全局配置文件的 XMLConfigBuilder 对象
XMLConfigBuilder xmlConfigBuilder = null;
// Configuration 对象
Configuration targetConfiguration;
Optional var10000;
if (this.configuration != null) {
// 判断是否存在 configuration对象,如果存在说明已经解析过了
targetConfiguration = this.configuration;
// 覆盖属性
if (targetConfiguration.getVariables() == null) {
targetConfiguration.setVariables(this.configurationProperties);
} else if (this.configurationProperties != null) {
targetConfiguration.getVariables().putAll(this.configurationProperties);
}
// 如果configuration对象不存在,但是存在configLocation属性,就根据mybatis-config.xml的文件路径来构建 xmlConfigBuilder对象
} else if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
// 属性'configuration'或'configLocation'未指定,使用默认MyBatis配置
LOGGER.debug(() -> {
return "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration";
});
targetConfiguration = new Configuration();
var10000 = Optional.ofNullable(this.configurationProperties);
Objects.requireNonNull(targetConfiguration);
var10000.ifPresent(targetConfiguration::setVariables);
}
// 设置 Configuration 中的属性 即我们可以在Mybatis和Spring的整合文件中来设置 MyBatis的全局配置文件中的设置
var10000 = Optional.ofNullable(this.objectFactory);
Objects.requireNonNull(targetConfiguration);
var10000.ifPresent(targetConfiguration::setObjectFactory);
var10000 = Optional.ofNullable(this.objectWrapperFactory);
Objects.requireNonNull(targetConfiguration);
var10000.ifPresent(targetConfiguration::setObjectWrapperFactory);
var10000 = Optional.ofNullable(this.vfs);
Objects.requireNonNull(targetConfiguration);
var10000.ifPresent(targetConfiguration::setVfsImpl);
Stream var24;
if (StringUtils.hasLength(this.typeAliasesPackage)) {
var24 = this.scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream().filter((clazz) -> {
return !clazz.isAnonymousClass();
}).filter((clazz) -> {
return !clazz.isInterface();
}).filter((clazz) -> {
return !clazz.isMemberClass();
});
TypeAliasRegi