mybatis源码学习(四)--springboot整合mybatis原理

我们接下来说:springboot是如何和mybatis进行整合的
1.首先,springboot中使用mybatis需要用到mybatis-spring-boot-start,可以理解为mybatis开发的整合springboot的jar包
有一个关键点先说明:前面也提到过,不管是mybatis和spring整合,还是和springboot整合,都需要做两个操作:
   1.把当前接口和对应的mapperProxyFactory存入到knownMappers中,
   2.把sql包装成mappedStatement,存入到mappedStatements这个map中
 
 
1.springboot项目中,@SpringbootApplication注解上,有一个@EnableAutoConfiguration注解,而@EnableAutoConfiguration注解又利用了@Import注解,注入了一个ImportSelector的实现类 AutoConfigurationImportSelector.class
2.AutoConfigurationImportSelector在selectImports()方法中有一行重要的代码:
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
 
   这行代码内部,会从所有jar包中,META-INF/spring.factories文件中,加载EnableAutoConfiguration对应的实现类,那mybatis-spring-boot-autoconfigure.jar包中,配置了两个实现类,
 
   
1 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
3 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
 
3.我们来说 MybatisAutoConfiguration.class
  
  
1 @org.springframework.context.annotation.Configuration
2   @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
3   @ConditionalOnSingleCandidate(DataSource.class)
4   @EnableConfigurationProperties(MybatisProperties.class)
5   @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
6   public class MybatisAutoConfiguration implements InitializingBean {
7  
8  
9   }
 
  这里有一个点,就是 @EnableConfigurationProperties(MybatisProperties.class);点开MybatisProperties.class文件会发现,这里面声明的就是,在application.properties配置文件中,mybatis提供的配置信息:比如mybatis.mapper-locations=classpath:mapping/*Mapper.xml;这个点,不细说了,后面可能会写一篇自定义starter的学习笔记,到时候 再详细写
 
4.在MybatisAutoConfiguration中有一个静态内部类 AutoConfiguredMapperScannerRegistrar 实现了ImportBeanDefinitionRegistrar;
   所以,spring在refresh的时候,会执行这个类的 registerBeanDefinitions()方法,将 MapperScannerConfigurer存到了beanDefinitionMap中
 1 @Override
 2 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 3  
 4  
 5   if (!AutoConfigurationPackages.has(this.beanFactory)) {
 6     logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
 7     return;
 8   }
 9   //中间删除了部分代码
10   registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
11 }
 
5.MapperScannerConfigurer是BeanDefinitionRegistryPostProcessor的实现类,在refresh()  -->  invokeBeanFactoryPostProcessors(beanFactory)中,会遍历所有beanFactoryPostProcessor和BeanDefinitionRegistrtPostProcessor的实现类,依次执行postProcessorBeanDefinitionRegistrar()方法
 
   MapperScannerConfigurer的postProcessBeanDefinitionRegistry()方法,会执行扫描方法,这里的扫描方法,和mapperScannerRegistrar的registerBeanDefinitions中的doScan是一样的,这里扫描的包是在,初始化MapperScannerConfigurer的时候,在执行完属性注入之后,调用了截图中的方法,把当前pvs中的basePackage传到MapperScannerConfigurer中,这里是如何传过去的,待研究
 
 
 
6.在将mapper扫描完之后,需要进行sql的解析,在和springboot整合之后,需要在配置文件中配置当前要扫描的mapper.xml文件,
   mybatis.mapper-locations=classpath:mapping/*Mapper.xml
 
   这里的mapperLocation,是在sqlSesionFactorybean中进行解析的,在第3步中的自动配置类中,通过@Bean,注入了SqlSessionFactory,
   在sqlSessionFactory()方法最后,会调用factoryBean.getObject()方法,这里其实调用的就是SqlSessionFactory的getObject()方法,
 
   
1 @Override
2   public SqlSessionFactory getObject() throws Exception {
3     if (this.sqlSessionFactory == null) {
4       afterPropertiesSet();
5     }
6  
7  
8     return this.sqlSessionFactory;
9   }
 
 
从afterPropertiesSet()方法,一直往下追,会追到同类中的buildSqlSessionFactory()方法,在这个方法中,判断如果当前mapperlocation不为null,就进行解析
 
 
  
 1 if (this.mapperLocations != null) {
 2       if (this.mapperLocations.length == 0) {
 3         LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");
 4       } else {
 5         for (Resource mapperLocation : this.mapperLocations) {
 6           if (mapperLocation == null) {
 7             continue;
 8           }
 9           try {
10             XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
11                 targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
12             xmlMapperBuilder.parse();
13           } catch (Exception e) {
14             throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
15           } finally {
16             ErrorContext.instance().reset();
17           }
18           LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
19         }
20       }
21     }
 
在xmlMapperBuilder.parse()就是原生mybatis在解析xml文件时,需要调用的方法
 
 
7.在service中注入mapper接口,在初始化service,注入依赖的mapper接口时,还是调用的mapperFactorybean.getObject()方法来获取代理对象
 
springboot整合mybatis  和 spring+mybatis整合时,解析xml文件有一个区别:
  spring-mybatis是利用mapperFactorybean的checkDao()方法来解析xml,put数据到mappedStatement和knowmappers
 
 springboot是利用SqlSessionFactoryBean的getObject()来解析xml,put数据到mappedStatement和knowMappers 
 

猜你喜欢

转载自www.cnblogs.com/mpyn/p/12079855.html