持续更新…
环境搭建
1、仓库地址
2、搭建步骤
准备工作:IDEA-2021、maven-3.3.9、JDK-8
①、pom.xml
创建普通的 maven 工程,修改 pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.micozone</groupId>
<artifactId>SpringBoot-2.2.1.RELEASE</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<!--名字中包含spring-boot-starter的jar包主要作用为聚合其他jar包,并无代码-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
</dependencies>
</project>
②、启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
一、springApplication.run();
SpringApplication.run(); 主要有两步,第一步:new SpringApplication(); 第二步:springApplication.run(); 作为第一大部分
new SpringApplication();
new SpringApplication(); 中会对 springApplication 对象的一些属性赋值,主要有:
A:initializers = 所有 spring.factories 文件中 ApplicationContextInitializer 接口的实现类,其中 initializers 的类型为 List
B:listeners = 所有 spring.factories 文件中 ApplicationListener 接口的实现类,其中 listeners 的类型为 List
C:primarySource = [App.class]
其中 A 和 B 中,会调用 SpringFactoriesLoader.loadFactoryNames(); 其中第二次加载 ApplicationListener 的子类时,会使用到缓存(SpringFactoriesLoader 类有一个属性:cache,cache 的类型为:Map<ClassLoader, MultiValueMap<String, String>>),那是因为第一次加载 ApplicationListener 的子类时,已经把 spring.factories 文件中的所有数据存到 SpringFactoriesLoader.cache 中了。
1、getRunListeners(args); listeners.starting();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
收集 spring.factories 文件中所有 SpringApplicationRunListener 接口的实现类,然后调用这些对象的 starting();
SpringBoot 2.2.1.RELEASE 包中的 spring.factories 文件中有 SpringApplicationRunListener=EventPublishingRunListener
EventPublishingRunListener使用到发布者模式,EventPublishingRunListener有一个属性 initialMulticaster,initialMulticaster 中收集了 springApplication 对象 listeners 属性的所有监听器,在调用不同的方法如 starting(); environmentPrepared(); 时,会通知相应的监听器执行 onApplicationEvent();
2、prepareEnvironment();
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
将所有环境信息封装到 configurableEnvironment 对象中(包括系统属性、系统环境变量、application.yml等),其中会执行 eventPublishingRunListener.environmentPrepared(environment);
3、createApplicationContext(); prepareContext(); refreshContext(); afterRefresh();
ConfigurableApplicationContext context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
A、创建应用上下文
实际上创建的是 AnnotationConfigServletWebServerApplicationContext。
AnnotationConfigServletWebServerApplicationContext 的无参构造中会为两个重要的属性赋值:
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
其中 AnnotatedBeanDefinitionReader 注册的 beanDefinition 类型为 AnnotatedGenericBeanDefinition,ClassPathBeanDefinitionScanner 注册的 beanDefinition 类型为 ScannerGenericBeanDefinition。
并且 AnnotatedGenericBeanDefinition 的无参构造中会注册一个非常重要的 beanDefinition:ConfigurationClassPostProcessor。
B、应用上下文的准备工作
执行 applicationContextInitialization.initialize(context);
执行 eventPublishingRunListener.contextPrepared(context);
执行 beanDefinitionLoader.load(App.class);
执行 eventPublishingRunListener.contextLoaded(context);
C、应用上下文的刷新工作
应用上下文的刷新工作 作为第二大部分
D、应用上下文刷新后的工作
无代码逻辑
4、listeners.started(); callRunners(); listeners.running();
listeners.started(context);
callRunners(context, applicationArguments);
listeners.running(context);
A、eventPublishingRunListener.started();
B、调用所有实现 ApplicationRunner、CommandLineRunner 接口的 bean 对象的 run();
C、eventPublishingRunListener.running();
二、abstractApplicationContext.refresh();
首先获取到 applicationContext.beanFactory(); 作为每个方法的参数,其中 beanFactory 的实际类型为 DefaultListableBeanFactory
1、prepareBeanFactory(beanFactory);
TODO
beanFactory 的准备工作。
1、添加 bean 后置处理器:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
2、添加忽略依赖注入的接口:beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
3、针对类型为接口的 bean,指定哪个实现类作为实际的 bean 对象:beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
4、注册单例 bean (直接添加到一级缓存中):beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
2、invokeBeanFactoryPostProcessors(beanFactory);
调用 beanFactory 的后置处理器。
方法调用维度,先调用 beanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry); 该方法的主要作用就是注册 beanDefinition,或者修改 beanDefinition,其中执行的最重要的方法就是 configurationClassPostProcessor.postProcessBeanDefinitionRegistry(); 该方法会先收集 beanFactory.beanDefinitionNames 集合中含有 @configuration 注解的 beanName 对应的 mergedBeanDefinitions 集合中的 rootBeanDefinition 对象(一般只有启动类),该方法会针对每一个 rootBeanDefinition,调用 configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass); 作为第三大部分;然后再调用 beanFactoryPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory); 该方法的主要作用就是修改 beanFactory。
对象处理维度,先处理 applicationContext.beanFactoryPostProcessors,然后再处理 beanFactory.beanDefinitionNames 中的 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 接口的实现类。
3、registerBeanPostProcessors(beanFactory);
将 beanDefinitionNames 中所有实现 beanPostProcessor 的 beanName,提前调用 getBean(beanName); 加载 bean 并放到 beanPostProcessors 集合中。
4、finishBeanFactoryInitialization(beanFactory);
完成 beanFactory 的 初始化,主要完成单例 bean 的加载工作:beanFactory.preInstantiateSingletons(); 作为第四大部分
三、configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass);
1、@PropertySource
解析 @PropertySource,value 为 properties 文件数组,将 properties 文件中所有的键值对保存到 environment 对象中,可以通过 @Value(“${user.name}”) 取值。
2、@ComponentScan
通过 classPathBeandefinitionScanner.doScan(); 默认扫描当前包以及子包下含有 @Component 的类或接口,封装为 ScannerGenericBeanDefinition 对象,通过 beanFactory.registryBeanDefinition(); 注册到 beanDefinitionMap、beanDefinitionNames 中;
针对每一个扫描到的 beanDefinition,封装为指定对象作为参数继续调用 configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass);
3、@Import
4、@Bean
针对每一个含有 @Bean 注解的方法,最终都会调用 registry.registerBeanDefinition(beanName, beanDefToRegister); 该方法会将返回值封装到 beanDefinitionMap、beanDefinitionNames 中。
四、beanFactory.preInstantiateSingletons();
遍历 beanDefinitionNames 集合,根据 beanName 获取 mergedBeanDefinitions 中的 rootBeanDefinition 对象,根据 rootBeanDefinition 判断 对象是否满足:非抽象类、是单例、非懒加载,如果都满足调用 getBean(beanName); 加载 bean。
1、getBean(beanName);
return doGetBean();
2、doGetBean();
A、getSingleton(beanName);
先查一级缓存(singletonObjects),查到返回,没查到判断 singletonsCurrentlyInCreation 集合是否包含 beanName,如果包含说明是第二次调用 getBean(beanName); 此时查询二级缓存(earlySingletonObjects),查到返回,没查到查三级缓存(singletonFactories),如果查到将值从三级缓存迁移至二级缓存并返回。
如果查到值,直接调用 getObjectForBeanInstance(); 逻辑结束。
B、getSingleton(beanName,ObjectFactory);
ObjectFactory 是函数式接口,getObject(); 中调用了createBean();
1、查一级缓存
查到直接返回,没查到继续往下进行。
2、singletonsCurrentlyInCreation.add(beanName);
将 beanName 添加到 singletonsCurrentlyInCreation 集合中。
3、createBean();
createBean(); 作为四.3部分
4、singletonsCurrentlyInCreation.remove(beanName);
5、将完整 bean 添一、删二三
C、getObjectForBeanInstance();
该方法无论如何都会被调用。
如果 beanName 以 & 开头或者不实现 FactoryBean 接口,直接返回 bean 实例。
如果 beanName 不以 & 开头并且实现 FactoryBean 接口,先根据 beanName 查缓存,缓存中没有再调用 getObject(); 获取真正的 bean,将 bean 放到缓存中,并返回。
3、createBean();
A、resolveBeforeInstantiation();
执行 beanPostProcessors 中实现 InstantiationAwareBeanPostProcessor 接口的 beanPostProcessor 的 postProcessBeforeInstantiation(beanClass, beanName); 如果方法的返回值不为null,直接return,
不执行 doCreateBean(beanName, …);
B、doCreateBean();
doCreateBean(beanName, …); 作为四.4部分
4、doCreateBean();
A、实例化 bean:createBeanInstance();
如果 beanDefinition.instanceSupplier 有值,直接调用 instanceSupplier.get(); 获取 bean 实例;
否则通过反射调用构造函数对象的 newInstance(); 实例化 bean。
B、属性赋值:populateBean();
在属性赋值前,判断 singletonsCurrentlyInCreation 是否包含 beanName,如果包含添三删二。
如果属性上有 @Resource,在执行 beanPostProcessors 中实现 InstantiationAwareBeanPostProcessor 接口的 beanPostProcessor 的 postProcessProperties(); 时,commonAnnotationBeanPostProcessor.postProcessProperties(); 逻辑中会通过反射对 @Resource 修饰的属性赋值:field.set(currentBean,otherBean); 其中 otherBean 会先查一级缓存,查询直接对属性赋值,如果没查到会调用 getBean(otherBean);
C、初始化 bean:initializeBean();
1、invokeAwareMethods();
如果 bean 实现指定 aware 接口,调用 setXXX();
2、beanPostProcessor.postProcessBeforeInitialization();
执行 beanPostProcessors 集合中每一个 beanPostProcessor 的 postProcessBeforeInitialization();
其中 commonAnnotationBeanPostProcessor.postProcessBeforeInitialization(); 中会判断是否存在含有 @PostConstruct 的方法,如果有,执行该方法。
3、invokeInitMethods();
如果 bean 实现 InitializingBean 接口,调用 afterPropertiesSet();
4、beanPostProcessor.postProcessAfterInitialization();
执行 beanPostProcessors 集合中每一个 beanPostProcessor 的 postProcessAfterInitialization();