日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

當用SpringApplication.run的時候發生了什么(一)

 

提問

- 服務啟動的時候,SpringApplication內部做了什么?
- 創建上下文的時候是使用的哪一種ApplicationContext?
- Bean 是在哪個步驟定義的,BeanDefinition怎么排序的?
- Bean 是在哪個步驟創建和初始化的?
- 監聽器有什么作用,都發布了哪些事件?

本篇文章主要介紹Bean是什么時候定義的,及Bean是如何創建的。

實例講解

application.yml

client:
  id: 1
  server: localhost

MyClientAutoConfiguration

@Configuration
@EnableConfigurationProperties(ClientProperties.class)
@ConditionalOnProperty(prefix = "client", name = "enable", havingValue = "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

@SpringBootApplication
public class ConditionalBootStrap {
?
    public static void main(String[] args) {
        SpringApplication.run(ConditionalBootStrap.class, args);
    }
}

當服務啟動的時候,大家可以先猜測一下,哪些Bean會被注冊(registerBeanDefinition)?

結合源碼講解

讓我們直接達到 SpringApplication.run 中的 refreshContext 方法,看看里面做了什么?

@Override
    public 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 = "true") 不滿足條件,yml中沒有 client.enable=true,所以 ConditionEvaluator#shouldSkip=true,就被跳過了。

問:為什么內部類 MyClientConfiger 和 ClientConfiger是有效的?

答:因為這兩個類都是 @Configuration Class ,而且 ConditionEvaluator#shouldSkip=false ;@ConditionalOnProperty(matchIfMissing = true) 中 matchIfMissing=true的意思是如果沒有找到匹配的也放行。

  1. 獲取BeanMethod

所謂BeanMethod 就是標有@Bean的方法

上面實例中標有@Bean 的方法有:

MyClientAutoConfiguration#client1 方法 和 MyClientAutoConfiguration$ClientConfiger#client2 方法,但是因為MyClientAutoConfiguration類不符合條件,所以client1 bean method也是無效的,到這里獲取到的 BeanMethod 只有client2

當用SpringApplication.run的時候發生了什么(一)

 

將此BeanMethod進行注冊,即
registry.registerBeanDefinition(beanName, beanDefToRegister)。

到目前為止在此過程中注冊了3個BeanDefinition, 即MyClientConfiger 和 ClientConfiger ,及client2,那么MyClientConfiger 和 ClientConfiger的順序是怎么控制的?

BeanDefinitions 的順序是什么樣的?

在上面步驟中我們說了,獲取basePackages下的所有類(getResources),那么Class的順序就是在getResources 過程中改變:

protected File[] listDirectory(File dir) {
        File[] files = dir.listFiles();
        if (files == null) {
            if (logger.isInfoEnabled()) {
                logger.info("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");
            }
            return new File[0];
        }
        Arrays.sort(files, Comparator.comparing(File::getName));
        return files;
    }

從上面源碼中我們可以看到,如果是文件,那么是根據文件名進行排序的,排序后變成

當用SpringApplication.run的時候發生了什么(一)

 

那么如果是Jar文件呢,大家可以看下源碼,是根據JarFile解壓之后的順序。

finishBeanFactoryInitialization

此方法主要完成BeanDefinition -> Bean的過程。

當用SpringApplication.run的時候發生了什么(一)

 

這里或按照順序依次遍歷之前的 BeanDefinitions,然后進行 getBean -> createBean -> initialize ,但是有個地方需要注意就是當一個Bean創建/初始化過程中如果需要/依賴其他的Bean,且這個依賴的Bean 還沒有創建的時候,則優先會創建這個Bean(doResolveDependency),比如:

 @Autowired
 public MyClientConfiger(MyClient client) {
        this.client = client;
 }

MyClientConfiger 在創建Bean初始化過程中,發現構造函數中需要依賴 MyClient 類型的Bean ,此時就會優先創建MyClient Bean ,即beanName=client2,如果沒有找到這個BeanDefinition,則此時就會報錯 throw new
NoSuchBeanDefinitionException
 。

好了,Bean定義和創建的過程已經講完了,下面我拋一個問題給大家,假如我把 client.enable=true 配置加上會發生什么?

client:
  id: 1
  server: localhost
  enable: true

分享到:
標簽:SpringApplication run
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定