springboot集成mybatis源碼分析-啟動加載mybatis過程(二)


1、springboot項目最核心的就是自動加載配置,該功能則依賴的是一個注解@SpringBootApplication中的@EnableAutoConfiguration

2、EnableAutoConfiguration主要是通過AutoConfigurationImportSelector類來加載

  以mybatis為例,*selector通過反射加載spring.factories中指定的java類,也就是加載MybatisAutoConfiguration類(該類有Configuration注解,屬於配置類)

  

  

  

 16 package org.mybatis.spring.boot.autoconfigure; 60 重點:SqlSessionFactory 和 SqlSessionTemplate 兩個類
 61 /**
 62  * {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a
 63  * {@link SqlSessionFactory} and a {@link SqlSessionTemplate}.
 64  *
 65  * If {@link org.mybatis.spring.annotation.MapperScan} is used, or a
 66  * configuration file is specified as a property, those will be considered,
 67  * otherwise this auto-configuration will attempt to register mappers based on
 68  * the interface definitions in or under the root auto-configuration package.
 69  *
 70  * @author Eddú Meléndez
 71  * @author Josh Long
 72  * @author Kazuki Shimizu
 73  * @author Eduardo Macarrón
 74  */
 75 @org.springframework.context.annotation.Configuration  76 @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
 77 @ConditionalOnBean(DataSource.class)
 78 @EnableConfigurationProperties(MybatisProperties.class)
 79 @AutoConfigureAfter(DataSourceAutoConfiguration.class)
 80 public class MybatisAutoConfiguration {
 81 
 82   private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
 83  //與mybatis配置文件對應
 84   private final MybatisProperties properties;
 85 
 86   private final Interceptor[] interceptors;
 87 
 88   private final ResourceLoader resourceLoader;
 89 
 90   private final DatabaseIdProvider databaseIdProvider;
 91 
 92   private final List<ConfigurationCustomizer> configurationCustomizers;
 93 
 94   public MybatisAutoConfiguration(MybatisProperties properties,
 95                                   ObjectProvider<Interceptor[]> interceptorsProvider,
 96                                   ResourceLoader resourceLoader,
 97                                   ObjectProvider<DatabaseIdProvider> databaseIdProvider,
 98                                   ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
 99     this.properties = properties;
100     this.interceptors = interceptorsProvider.getIfAvailable();
101     this.resourceLoader = resourceLoader;
102     this.databaseIdProvider = databaseIdProvider.getIfAvailable();
103     this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
104   }
105  //postConstruct作用是在創建類的時候先調用,  校驗配置文件是否存在
106   @PostConstruct
107   public void checkConfigFileExists() {
108     if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
109       Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
110       Assert.state(resource.exists(), "Cannot find config location: " + resource
111           + " (please add config file or check your Mybatis configuration)");
112     }
113   }
114   //conditionalOnMissingBean作用:在沒有類的時候調用,創建sqlsessionFactory  sqlsessionfactory最主要的是創建並保存了Configuration類
115   @Bean
116   @ConditionalOnMissingBean
117   public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
118     SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
119     factory.setDataSource(dataSource);
120     factory.setVfs(SpringBootVFS.class);
121     if (StringUtils.hasText(this.properties.getConfigLocation())) {
122       factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
123     }
124     Configuration configuration = this.properties.getConfiguration();
125     if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
126       configuration = new Configuration();
127     }
128     if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
129       for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
130         customizer.customize(configuration);
131       }
132     }
133     factory.setConfiguration(configuration);
134     if (this.properties.getConfigurationProperties() != null) {
135       factory.setConfigurationProperties(this.properties.getConfigurationProperties());
136     }
137     if (!ObjectUtils.isEmpty(this.interceptors)) {
138       factory.setPlugins(this.interceptors);
139     }
140     if (this.databaseIdProvider != null) {
141       factory.setDatabaseIdProvider(this.databaseIdProvider);
142     }
143     if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
144       factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
145     }
146     if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
147       factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
148     }
149     if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
150       factory.setMapperLocations(this.properties.resolveMapperLocations());
151     }
152 
153     return factory.getObject();
154   }
155 
156   @Bean
157   @ConditionalOnMissingBean
158   public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
159     ExecutorType executorType = this.properties.getExecutorType();
160     if (executorType != null) {
161       return new SqlSessionTemplate(sqlSessionFactory, executorType);
162     } else {
163       return new SqlSessionTemplate(sqlSessionFactory);
164     }
165   }
238 }

3、MybatisAutoConfiguration:

①類中有個MybatisProperties類,該類對應的是mybatis的配置文件

②類中有個sqlSessionFactory方法,作用是創建SqlSessionFactory類、Configuration類(mybatis最主要的類,保存着與mybatis相關的東西)

③SelSessionTemplate,作用是與mapperProoxy代理類有關

4、關注下Configuration中的MapperRegister類,該類是創建dao(mapper的代理類),后續具體執行dao查詢操作的都是基於該類的

 

下邊是springboot項目啟動棧信息:

1、springboot啟動調用SpringApplication的靜態方法run

  

2、進入run方法:先進行springboot相關初始化

  

3、進入refreshContext方法:初始化springboot的上下文

4、進入refresh方法(AbstractApplicationContext)

5、通過beanfactory實力各種bean

。。。。

6、在ConfigurationClassBeanDefinitionReader類來注冊加載所有的spring.facotrys中指定的類

7、最后到MybatisAutoConfiguration的registerBeanDefinition方法中,並且在new classPathMapperScanner對象中會配置environment

8、通過ClassPathMapperScanner掃描mapper文件

9、進入scanner的doscan方法(其實調用的是父類的doScan方法)

 10、進入父類ClassPathBeanDefinitionScanner類的doScan方法(其中basePackages就是application的包路徑,這個包路徑其實就是@springBootApplication注解中的一個主機ComponentScan類得到的)

11、在findCandidateComponents中返回Set集合(mapper類的集合)

。。。。

12、當springboot調用getBean方法是才是真正創建類的時候

13、最終到創建MybatisAutoConfiguration類了

在創建之前會調用checkConfigFileExists方法(因為方法上有@PostConstruct),校驗mybatis配置文件是否存在

14、以上校驗完之后,到注入屬性

  注入的時候通過beanname調用getbean方法來獲取一個bean

15、在doGetBean方法中通過getSigngton(name)方法來獲取已經注冊過得bean,注冊的bean都存在DefaultSingletonBeanRegister類的SingtonObjects的map對象中

 

另外該map對象中還存了這些bean:

  SqlsessionFactory:

  

  與事務相關的bean:

  

  環境變量:

  

  數據源配置bean:

  

  sqlSessionTemplate:

  

  等等。。。。

16、getbean最終通過MapperFactoryBean中的getObject方法來獲取,其中getSqlSession方法返回的是SqlSessionTemplate,也就是getMapper調用的是SQLSessionTemplate中

的方法

17、進去到SqlSessionTemplage,getMapper實際上是從Configuration對象中類獲取mapper

18、進去到Configuration中,getMapper實際上是從MapperRegister對象中獲取的

19、進入到MapperRegister中,getMapper是從knownMappers 的map對象中來獲取的,獲取到mapperProxyFactory后,mapper工廠通過newInstance來創建一個mapperProxy

代理對象

 

 

20、這個mapperProxy就是在使用userdao的時候的代理類

 


免責聲明!

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



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