一 当用SpringApplication.run的时候发生了什么


一 当用SpringApplication.run的时候发生了什么

文章插图
【一 当用SpringApplication.run的时候发生了什么】 
提问- 服务启动的时候,SpringApplication内部做了什么?- 创建上下文的时候是使用的哪一种ApplicationContext?- Bean 是在哪个步骤定义的,BeanDefinition怎么排序的?- Bean 是在哪个步骤创建和初始化的?- 监听器有什么作用,都发布了哪些事件?本篇文章主要介绍Bean是什么时候定义的,及Bean是如何创建的 。
实例讲解application.yml
client:id: 1server: localhostMyClientAutoConfiguration
@Configuration@EnableConfigurationProperties(ClientProperties.class)@ConditionalOnProperty(prefix = "client", name = "enable", havingValue = https://www.isolves.com/it/cxkf/bk/2020-06-28/"true")public class MyClientAutoConfiguration {? private ClientProperties properties; @Autowired public MyClientAutoConfiguration(ClientProperties properties) { this.properties = properties; }? @Bean public MyClient client1() { return new MyClient(1); }?? @Configuration @ConditionalOnProperty(name = "client.valid", havingValue = "true", matchIfMissing = true) static class ClientConfiger {? @Bean public MyClient client2() { return new MyClient(2); }? @Configuration static class MyClientConfiger { private final MyClient client;? @Autowired public MyClientConfiger(MyClient client) { this.client = client; } } }}ConditionalBootstrap
@SpringBootApplicationpublic class ConditionalBootStrap {?  public static void main(String[] args) {      SpringApplication.run(ConditionalBootStrap.class, args);  }}当服务启动的时候,大家可以先猜测一下,哪些Bean会被注册(registerBeanDefinition)?
结合源码讲解让我们直接达到 SpringApplication.run 中的 refreshContext 方法,看看里面做了什么?
@Overridepublic void refresh() throws BeansException, IllegalStateException {...?try {...?// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);?...?// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);?}从源码中我们看看这两个方法主要是完成什么工作的 。
invokeBeanFactoryPostProcessors
Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given. Must be called before singleton instantiation
这个方法主要完成BeanDefinition的工作:
- 哪些Class 实现了 registerBeanDefinition?- BeanDefinitions 的顺序是什么样的?提示:到refreshContext这一步之前,有些内置的类和 primarySource(即 ConditionalBootStrap)已经放到了BeanDefinitionMap中
哪些Class 实现了 registerBeanDefinition?
  1. 首先会将之前的BeanDefinitionNames 循环,然后找出 @Configuration Class (isFullConfigurationClass || isLiteConfigurationClass)

一 当用SpringApplication.run的时候发生了什么

文章插图
 
  1. 解析每一个 @Configuration 类
通过ConfigurationClassParser#parse 解析上面的configCandidates:
  • 首先判断这个类是否有效,是否应该忽略,这个地方有个很重要的提示,目前版本Spring/SpringBoot 都是通过 ConditionEvaluator#shouldSkip 来判断一个类是否应该忽略(Determine if an item should be skipped based on {@code @Conditional} annotations)
  • 该类如果不应该忽略时,就会继续寻找该类是否有 @ComponentScan 注解(我们知道@SpringBootApplication 注解也包含 @Component注解)
  • 找到 @ComponentScan 注解后,使用 ComponentScanAnnotationParser#parse 完成 basePackages 下所有类的扫描(如果@ComponentScan中没有加basePackages,默认会使用primarySource类所在包为basePackages)

一 当用SpringApplication.run的时候发生了什么

文章插图
 
  • 获取basePackages下的所有类(getResources)
  • 循环每个类,并且判断是否是有效的没有被排除(不在excludeFilter内)是@Component类,或者是派生类(@Configuration等)而且不应该被跳过,即 ConditionEvaluator#shouldSkip = false
  • 将有效的类进行 registerBeanDefinition
到这一步时,可以猜一下上面实例中哪些类是有效的
一 当用SpringApplication.run的时候发生了什么

文章插图
 
这里你有没有疑问:
问:为什么MyClientAutoConfiguration类是无效的?
答:因为@ConditionalOnProperty(prefix = "client", name = "enable", havingValue = https://www.isolves.com/it/cxkf/bk/2020-06-28/"true") 不满足条件,yml中没有 client.enable=true,所以 ConditionEvaluator#shouldSkip=true,就被跳过了 。


推荐阅读