1、springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplication中的@EnableAutoConfiguration

2、EnableAutoConfiguration主要是通过AutoConfigurationImportSelector类来加载

  以mybatis为例,*selector通过反射加载spring.factories中指定的java类,也就是加载MybatisAutoConfiguration类(该类有Configuration注解,属于配置类)

  

  

  

 package org.mybatis.spring.boot.autoconfigure; 重点:SqlSessionFactory 和 SqlSessionTemplate 两个类
/**
* {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a
* {@link SqlSessionFactory} and a {@link SqlSessionTemplate}.
*
* If {@link org.mybatis.spring.annotation.MapperScan} is used, or a
* configuration file is specified as a property, those will be considered,
* otherwise this auto-configuration will attempt to register mappers based on
* the interface definitions in or under the root auto-configuration package.
*
* @author Eddú Meléndez
* @author Josh Long
* @author Kazuki Shimizu
* @author Eduardo Macarrón
*/
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
 //与mybatis配置文件对应
private final MybatisProperties properties; private final Interceptor[] interceptors; private final ResourceLoader resourceLoader; private final DatabaseIdProvider databaseIdProvider; private final List<ConfigurationCustomizer> configurationCustomizers; public MybatisAutoConfiguration(MybatisProperties properties,
ObjectProvider<Interceptor[]> interceptorsProvider,
ResourceLoader resourceLoader,
ObjectProvider<DatabaseIdProvider> databaseIdProvider,
ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
this.properties = properties;
this.interceptors = interceptorsProvider.getIfAvailable();
this.resourceLoader = resourceLoader;
this.databaseIdProvider = databaseIdProvider.getIfAvailable();
this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
}
 //postConstruct作用是在创建类的时候先调用, 校验配置文件是否存在
@PostConstruct
public void checkConfigFileExists() {
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)");
}
}
//conditionalOnMissingBean作用:在没有类的时候调用,创建sqlsessionFactory sqlsessionfactory最主要的是创建并保存了Configuration类
@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()));
}
Configuration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new Configuration();
}
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
factory.setConfiguration(configuration);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
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();
} @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);
}
}
}

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的时候的代理类

springboot集成mybatis源码分析-启动加载mybatis过程(二)的更多相关文章

  1. mybatis源码分析--如何加载配置及初始化

    简介 Mybatis 是一个持久层框架,它对 JDBC 进行了高级封装,使我们的代码中不会出现任何的 JDBC 代码,另外,它还通过 xml 或注解的方式将 sql 从 DAO/Repository ...

  2. MyBatis 源码篇-资源加载

    本章主要描述 MyBatis 资源加载模块中的 ClassLoaderWrapper 类和 Java 加载配置文件的三种方式. ClassLoaderWrapper 上一章的案例,使用 org.apa ...

  3. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  4. Mybatis源码分析之SqlSession和Excutor(二)

    通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)), 今天我们分析下Mybatis如何创建Sql ...

  5. 精尽Spring Boot源码分析 - 配置加载

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  6. Spring源码分析之-加载IOC容器

    本文接上一篇文章 SpringIOC 源码,控制反转前的处理(https://mp.weixin.qq.com/s/9RbVP2ZQVx9-vKngqndW1w) 继续进行下面的分析 首先贴出 Spr ...

  7. Mybatis源码解读-配置加载和Mapper的生成

    问题 Mybatis四大对象的创建顺序? Mybatis插件的执行顺序? 工程创建 环境:Mybatis(3.5.9) mybatis-demo,参考官方文档 简单示例 这里只放出main方法的示例, ...

  8. 第一次源码分析: 图片加载框架Picasso源码分析

    使用: Picasso.with(this) .load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg") . ...

  9. 源码分析: 图片加载框架Picasso源码分析

    使用: Picasso.with(this) .load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg") . ...

随机推荐

  1. android_模拟器调试

    找到adb_server adb_server connect

  2. 父元素高度设置为min-height,子元素高度设置为100%,但实际上子元素高度你知道是多少吗?

    前言 给父元素一个min-height,子元素设置height:100%. 代码 <!DOCTYPE html> <html> <head> <title&g ...

  3. Windows 通过批处理自动执行 linux服务器上面命令的办法

    1. 使用putty 下载地址 https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 直接使用 exe版本就可以 https:/ ...

  4. SpringCloud学习笔记:服务注册与发现Eureka(2)

    1. Eureka简介 Eureka是一个用于服务注册和发现的组件,分为Eureka Server和Eureka Client,Eureka Server为Eureka服务注册中心,Eureka Cl ...

  5. 【转】Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印。

    @2019-02-28 [小记] Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印.

  6. 省市区JSON

    行政编码 ViewBag.CssLinks = ""; 行政编码 中国和韩国行政编码选择.数据来自json文件,但在前端通过json对象调用. 注意本地方式,是将json文件作为对 ...

  7. RocketMQ_问题_启动控制台console报错,connect to <null> failed

    配置如图所示: 问题如图所示: 明明配置了nameserver参数为啥还是connect to null呢? 我的rocketmq部署在CentOS7虚拟机上,原来是没关闭防火墙,执行:systemc ...

  8. C#多态及接口

    直接看代码吧 using System; using static System.Console; namespace ConsoleApp { //使用abstract,抽象类或方法,不能使用vir ...

  9. Eclipse中的sysout与debug-遁地龙卷风

    (-1)调试 在读<<一个程序员的奋斗史>>时里面提到这是一件很low的事情,突然想到自己也一直用sysout, 我是一个有情怀的人! (0)sysout的坏处 之所以长久的使 ...

  10. DensePose: Dense Human Pose Estimation In The Wild(理解)

    0 - 背景 Facebook AI Research(FAIR)开源了一项将2D的RGB图像的所有人体像素实时映射到3D模型的技术(DensePose).支持户外和穿着宽松衣服的对象识别,支持多人同 ...