- Spring Boot 整合 MyBatis
- 导入依赖
- 其中,依赖了 mybatis-spring-boot-autoconfigure.jar
- 在mybatis-spring-boot-autoconfigure.jar 中的spring.factories中
- 自动装配了 MybatisAutoConfiguration 这个类
- 看看导入的 AutoConfiguredMapperScannerRegistrar 干了什么
- 他继承了 ImportBeanDefinitionRegistrar,通过registerBeanDefinitions可以向IOC容器中注入一些组件
- 所以,最终获取到的Bean实例,实际上是一个 MapperProxy 类型的
- 在执行查询语句的时候,就会嗲用MapperProxy#invoke 进行拦截
- 最终,调用sqlSession进行语句的执行
- SpringBoot整合 Mybatis的流程到此就完结
Spring Boot 整合 MyBatis
导入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
其中,依赖了 mybatis-spring-boot-autoconfigure.jar
在mybatis-spring-boot-autoconfigure.jar 中的spring.factories中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
自动装配了 MybatisAutoConfiguration 这个类
在这个类中,注入了如下几个组件
- sqlSessionFactory -> @Bean导入的
- sqlSessionTemplate -> @Bean导入的
- MapperScannerRegistrarNotFoundConfiguration -> @Configuration导入的
- @Import({ AutoConfiguredMapperScannerRegistrar.class }) 这个配置类中,又导入了 AutoConfiguredMapperScannerRegistrar
看看导入的 AutoConfiguredMapperScannerRegistrar 干了什么
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware
他继承了 ImportBeanDefinitionRegistrar,通过registerBeanDefinitions可以向IOC容器中注入一些组件
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
logger.debug("Searching for mappers annotated with @Mapper");
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
try {
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
for (String pkg : packages) {
logger.debug("Using auto-configuration base package '{}'", pkg);
}
}
scanner.setAnnotationClass(Mapper.class);
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(packages));
} catch (IllegalStateException ex) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
}
}
其中的逻辑为:
- ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); 创建一个类路径下的Mapper扫描器
- scanner.setAnnotationClass(Mapper.class); 设置扫描的类型
- scanner.registerFilters(); 注册过滤规则
- scanner.doScan(StringUtils.toStringArray(packages)); 进行扫描,将感兴趣的Mapper类型的组件,注册到IOC容器中
- ClassPathBeanDefinitionScanner#doScan() 会调用到父类的doScan方法
- findCandidateComponents(basePackage) 找寻候选的组件
- 在findCandidateComponents 中将会调用isCandidateComponent 来进行判断是否为候选的组件
- 在本类中,将会调用 ClassPathMapperScanner#isCandidateComponent 来进行判断
其逻辑就是要把Mapper类型的接口那些类都扫描进来
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
- processBeanDefinitions(beanDefinitions); 然后对这些扫描出来的bean定义进行后置处理
其中的逻辑为
- 设置bean组件初始化时调用的构造函数类型
- 设置bean定义的实际类型(在IOC容器进行bean初始化的时候,将会初始化的是这个类型)
- 给bean组件的属性进行赋值(addToConfig,sqlSessionFactory,sqlSessionTemplate)
- 设置bean组件的自动装配类型 ```java definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59 definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add(“sqlSessionTemplate”, this.sqlSessionTemplate);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
<a name="D2ldc"></a>
## 至此,Mybatis的自动装配已经完成
<a name="bN4P8"></a>
### 在我们调用Mapper进行sql查询的时候,实际上,获取的类型是上面进行后置处理时,修改成的MapperFactoryBean类型
<a name="lUSxX"></a>
### 而MapperFactoryBean又是一个FactoryBean类型,在IOC进行getBean的时候,会调用getObject() 获取实际的类型
具体流程图下
- getObject
- getSqlSession().getMapper(this.mapperInterface); # SqlSessionTemplate#getMapper 在自动装配过程中注入到IOC容器中,且通过后置处理,将其设置到MapperFactoryBean的属性中
- getConfiguration().getMapper(type, this); # 调用Configuration
- mapperRegistry.getMapper(type, sqlSession); # 调用MapperRegistry类
```java
# MapperRegistry#getMapper源码
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
- mapperProxyFactory.newInstance(sqlSession); # 最终调用MapperProxyFactory的newInstance创建代理对象
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
所以,最终获取到的Bean实例,实际上是一个 MapperProxy 类型的
在执行查询语句的时候,就会嗲用MapperProxy#invoke 进行拦截
最终,调用sqlSession进行语句的执行