一 当用SpringApplication.run的时候发生了什么
文章插图
【一 当用SpringApplication.run的时候发生了什么】
提问
- 服务启动的时候,SpringApplication内部做了什么?- 创建上下文的时候是使用的哪一种ApplicationContext?- Bean 是在哪个步骤定义的,BeanDefinition怎么排序的?- Bean 是在哪个步骤创建和初始化的?- 监听器有什么作用,都发布了哪些事件?
本篇文章主要介绍Bean是什么时候定义的,及Bean是如何创建的 。实例讲解application.yml
client:id: 1server: localhost
MyClientAutoConfiguration@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?
- 首先会将之前的BeanDefinitionNames 循环,然后找出 @Configuration Class (isFullConfigurationClass || isLiteConfigurationClass)
文章插图
- 解析每一个 @Configuration 类
- 首先判断这个类是否有效,是否应该忽略,这个地方有个很重要的提示,目前版本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)
文章插图
- 获取basePackages下的所有类(getResources)
- 循环每个类,并且判断是否是有效的没有被排除(不在excludeFilter内)是@Component类,或者是派生类(@Configuration等)而且不应该被跳过,即 ConditionEvaluator#shouldSkip = false
- 将有效的类进行 registerBeanDefinition
文章插图
这里你有没有疑问:
问:为什么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,就被跳过了 。
推荐阅读
- 淘宝产品点击率多少算好 淘宝测款一般要多少个点击
- MySQL中另一种查询优化方案—重构查询的方式
- 一款好用、免费的数据恢复软件+磁盘管理工具
- 端口映射是怎么一个操作
- 电脑运行慢?并不是它的性能不行,关掉一个开关,让你电脑飞起来
- 给神经网络加一个按钮,AI将适用于所有人
- 华为二面凉凉:Linux+Redis+MySQL+算法+网络+Java一个都讲不清
- 如何成为一个合格的数据架构师?
- 淘宝店推广费用标准 一个淘宝店推广费用大概多少
- 东风|搭载三菱发动机 东风风行·游艇正式发布:年轻人的第一台MPV来了