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 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM