spring boot整合mybaits源码分析
既然是分析spring boot整合mybatis,那么肯定需要看mybatis相关的autoConfiguration类–MybatisAutoConfiguration
MybatisAutoConfiguration
注解
首先看下MybatisAutoConfiguration这个类上都使用了哪些注解
// 是一个配置类
@Configuration
// 当类路径中存在SqlSessionFactory和SqlSessionFactoryBean才进行加载
@ConditionalOnClass({
SqlSessionFactory.class, SqlSessionFactoryBean.class })
// 当存在DataSource类型的bean时才进行加载
@ConditionalOnBean(DataSource.class)
// 将mybatis相关的配置都加载到MybatisProperties中
@EnableConfigurationProperties(MybatisPropertie.class)
// 在DataSourceAutoConfiguration加载之后进行加载
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
}
checkConfigFileExists
接下来看下checkConfigFileExists方法,该方法的主要作用就是判断是否指定了检查配置文件,如果指定了判断文件是否存在
@PostConstruct
public void checkConfigFileExists() {
// 判断mybatis.checkConfigLocation是否设置为true,并且mybatis.configLocation不为空,即指定了mybatis配置文件的路径
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)");
}
}
sqlSessionFactory
这个方法主要用来判断当前是否已经存在了一个SqlSessionFactory,如果不存在,那么会根据DataSource自动创建一个
@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()));
}
factory.setConfiguration(properties.getConfiguration());
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
return factory.getObject();
}
sqlSessionTemplate
这个方法的主要作用就是判断当前是否存在SqlSessionTemplate,如果不存在会根据SqlSessionFactory来创建一个
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
MapperScannerRegistrarNotFoundConfiguration
可以看到在MybatisAutoConfiguration内部又引入了一个配置类
// 是一个配置类
@Configuration
// 导入AutoConfiguredMapperScannerRegistrar
@Import({
AutoConfiguredMapperScannerRegistrar.class })
// 当不存在MapperFactoryBean类型时,才进行加载,因此如果另外使用了@MapperScan注解,并且扫描到了满足条件的类注入到了容器中,那么就不会执行
// 也就是说如果使用了@MapperScan注解,并且通过该注解扫描到了类并且进行了注入,那么@Mapper注解会失效
@ConditionalOnMissingBean(MapperFactoryBean.class)
public static class MapperScannerRegistrarNotFoundConfiguration {
@PostConstruct
public void afterPropertiesSet() {
log.debug(String.format("No %s found.", MapperFactoryBean.class.getName()));
}
}
这里的主要逻辑在AutoConfiguredMapperScannerRegistrar
AutoConfiguredMapperScannerRegistrar
AutoConfiguredMapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,因此会向容器中注册bean
这里的主要作用是在启动类Application所在的目录下,找到使用了@Mapper注解的类,然后生成对应的MapperFactoryBean,注册到容器中
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
log.debug("Searching for mappers annotated with @Mapper'");
// 通过容器的BeanDefinitionRegistry来创建一个ClassPathMapperScanner,因此在扫描的过程中可以向注册beanDefinition
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
try {
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
// 返回autoConfiguration的包名
List<String> pkgs = AutoConfigurationPackages.get(this.beanFactory);
for (String pkg : pkgs) {
log.debug("Using auto-configuration base package '" + pkg + "'");
}
// 只有使用了Mapper注解的类才会被处理
scanner.setAnnotationClass(Mapper.class);
// 注册过滤器,用来判断哪些类需要被处理,哪些类不需要被处理
scanner.registerFilters();
// 开始扫描,注册bean
scanner.doScan(StringUtils.toStringArray(pkgs));
} catch (IllegalStateException ex) {
log.debug("Could not determine auto-configuration " + "package, automatic mapper scanning disabled.");
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
ClassPathMapperScanner.registerFilters
这个方法的作用就是用来注册TypeFilter
- 如果指定了需要处理的注解类型,那么会注册一个AnnotationTypeFilter,用来判断类上是否使用了指定的注解
- 如果指定了markerInterface,那么会注册一个AssignableTypeFilter,用来判断类是否继承自指定的类
- 如果上述两个都没有指定,那么会处理指定包路径下面的所有类
public void registerFilters() {
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
// 如果指定了需要被处理的注解类型,那么会添加一个AnnotationTypeFilter的includeFilter,代表只有被annotationClass注解的类才会被处理
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces =