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 configurationCustomizers;
93
94 public MybatisAutoConfiguration(MybatisProperties properties,
95 ObjectProvider interceptorsProvider,
96 ResourceLoader resourceLoader,
97 ObjectProvider databaseIdProvider,
98 ObjectProvider> 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的时候的代理类