SpringBoot源码解析(1.4)-自动装配原理(总结)
自动装配概念
https://blog.csdn.net/sql2008help/article/details/123251638
前提条件
引入 SpringBoot 启动依赖,比方进行web开发需要引入web依赖,需要使用 mybatis 引入mybatis 依赖,这种启动依赖不仅可以简化原来依赖方式,还会引入autoconfig 依赖,SpringBoot 就是结合 AutoConfiguration 类帮我们初始化默认环境的。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
</dependencies>
以 mybatis 为例,mybatis-spring-boot-starter 依赖就包含了 mybatis 和 mybatis-spring 依赖,不需要像原来SSM开发模式一样 在pom.xml 中定义多个依赖,并且在 MybatisAutoConfiguration 类中会默认初始化一个 SqlSessionFactory ,不需要再自定义了
package org.mybatis.spring.boot.autoconfigure;
@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);
private final MybatisProperties properties;
private final Interceptor[] interceptors;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider) {
this.properties = properties;
this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable();
this.resourceLoader = resourceLoader;
this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable();
}
@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()));
}
。。。。。。。。
factory.setConfiguration(this.properties.getConfiguration());
。。。。。。。。
return factory.getObject();
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
}
}
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 位置如下:
① SpringApplication 实例化
SpringBoot 启动类通过调用 SpringApplication.run 方法启动容器,在静态run方法中实际是调用的SpringApplication 实例的run方法,在 SpringApplication 实例化的过程中调用loadFactoryNames方法从META-INF/spring.factories文件中读取配置并缓存至 SpringFactoriesLoader cache 中
org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames
具体查看:https://blog.csdn.net/sql2008help/article/details/123253292
② AnnotationConfigServletWebServerApplicationContext 实例化
AnnotationConfigServletWebServerApplicationContext 类( 以下用 context 代替 )在 spring-boot 包下,它继承至 ServletWebServerApplicationContext (同样在spring-boot包中),而ServletWebServerApplicationContext 继承至 spring-web 包中的 GenericWebApplicationContext 类,类图如下:
context 是SpringBoot 的核心,它包含读取注解的工具 AnnotatedBeanDefinitionReader ( reader ) 、注册和生产bean实例的工厂 DefaultListableBeanFactory (beanFactory)等关键属性,在 context 初始化过程中(实际是 reader 初始化时)会往 beanFactory 注册 ConfigurationClassPostProcessor(实现 BeanFactoryPostProcessor 接口) bean 定义
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
// 往 DefaultListableBeanFactory 注册一个 key 为 org.springframework.context.annotation.internalConfigurationAnnotationProcessor,BeanDefinition 为 ConfigurationClassPostProcessor 的后置处理器
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
具体查看:https://blog.csdn.net/sql2008help/article/details/123314453
③ AnnotationConfigServletWebServerApplicationContext refresh 方法
SpringApplication 在 run 方法中实例化 AnnotationConfigServletWebServerApplicationContext 后
开始调用 this.refreshContext(context); 方法,这个方法实际就是调用 context.refresh (父类org.springframework.context.support.AbstractApplicationContext refresh )方法
AbstractApplicationContext refresh 方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 填充 beanFactory 丰富 beanFactory 功能
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 执行 beanFactoryPostProcessors 对应方法
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
。。。。。。
// 完成bean实例化
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
。。。。。。
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
在 refresh 方法中重要的一个方法为:
this.invokeBeanFactoryPostProcessors(beanFactory);
这个方法接着调用 PostProcessorRegistrationDelegate 代理类的方法:
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
在此方法中完成 ConfigurationClassPostProcessor 的实例化,并执行
ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 方法,最终通过实例化出的 ConfigurationClassParser 对象完成启动类的解析
具体查看:https://blog.csdn.net/sql2008help/article/details/123354118
④ ConfigurationClassParser parse 方法 解析启动类
parser.parse(candidates); 解析启动类方法,该方法通过解析 @EnableAutoConfiguration 注解中 @Import({AutoConfigurationImportSelector.class}) 获取 AutoConfigurationImportSelector 类,最终通过调用 AutoConfigurationImportSelector.AutoConfigurationGroup 类的 process 方法 读取 META-INF/spring.factories 中 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的类名列表得到需要自动装配的类名,并根据结果实例化成ConfigurationClass对象后填充到org.springframework.context.annotation.ConfigurationClassParser 对象 Map<ConfigurationClass, ConfigurationClass> configurationClasses 属性 :
详情看:https://blog.csdn.net/sql2008help/article/details/123358545
⑤ bean 注册与实例化
自动装配的 bean 定义是在 AbstractApplicationContext refresh 方法中的 invokeBeanFactoryPostProcessors 方法里面完成的,具体代码为:
this.reader.loadBeanDefinitions(configClasses) :
bean 实例化则是由 AbstractApplicationContext refresh 方法中的 finishBeanFactoryInitialization 方法完成