前面說到IOC容器在刷新之前的一些初始化工作,現在來看看在refresh()方法中,是怎樣來加載注冊我們自己的bean定義的。
refresh()方法中有很多功能,從注釋中就可以看出來
我們本次重點關注invokeBeanFactoryPostProcessors(beanFactory);這個方法
該方法里面可以獲取到前面初始化好的注解讀取器AnnotatedBeanDefinitionReader,前面在AnnotationConfigUtils#registerAnnotationConfigProcessors方法中是往beanFactory里面注冊了配置類的處理器的ConfigurationClassPostProcessor,這個時候就可以拿出來使用了,創建一個配置類解析器對象ConfigurationClassParser,來具體處理幾種形式bean注入(@propertySource,@ComponentScan,@Import,@ImportResource,@bean),,最終再由ConfigurationClassBeanDefinitionReader將配置的bean定義加載到容器中ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
1.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法中判斷我們的beanFactory是否是bean定義注冊器,如果是就依次執行相應的bean定義處理器,進行注冊bean定義,否則執行依次執行相應的beanFactory處理器。
2.容器中如果已經實例化好的BeanFactoryPostProcessor先行執行
當然我們進行肯定是執行的bean注冊。
2.其次從beanFactory中獲取實現了PriorityOrdered接口的bean定義處理器。如果有的話立馬對它進行實例化。PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors這個方法是關鍵,ConfigurationClassPostProcessor這個類就是實現PriorityOrdered接口的處理器
3.現在就看ConfigurationClassPostProcessor類中怎么處理來bean定義的注冊了。ConfigurationClassPostProcessor#processConfigBeanDefinitions方法拿到目前已有的bean定義,判斷哪些是處理過了的,哪些是還需要處理。如果沒有就返回了。實際上最終會拿到我們自己的配置類我們標注了@Configuration注解的類。
4.ConfigurationClassParser#parse方法到doProcessConfigurationClass真正解析我們的配置類,解析@PropertySource,@ComponentScan,@Import,@ImportResource,@Bean這些注解,掃描注解就包含了掃描到@Component,@service,@Controller這些注解
5.掃描的時候會將將配置信息放一個掃描對象中去,然后執行ClassPathBeanDefinitionScanner的parse方法到doScan方法對包進行掃描,也就是會將@Component,@service,@Controller這些注解的類掃描注冊。完了這里還有重復檢查操作,萬一這些注解類上面還有其他配置,再次進行解析。
6.然后解析@Import和@Bean注解不過這兩個注解導入的類,在這里並不會立馬注冊到beanFactory中
7.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions到loadBeanDefinitionsForConfigurationClass方法里面才會去將@Import和@bean注解導入類加入bean定義中。至此PriorityOrdered類型的bean定義解析器(ConfigurationClassPostProcessor)就執行完畢,到這里我們自己所配置的那些類的定義也注冊到了容器中了。
8.接下來是實現了Ordered接口的bean定義解析器的執行,一般來說是沒有的,如果我們自己有配置實現這個類型的bean定義解析器,就會在這個階段立馬實例化然后執行它的postProcessBeanDefinitionRegistry方法。
9.在接着就是沒有執行過的其他類型bean定義解析器也會被立馬實例化執行。比如我們自己實現BeanDefinitionRegistryPostProcessor這個接口的bean定義處理器就是在這個地方執行了。這個時候第三方包中的類的定義都已經注冊好了,這個時候我們想要新加自己的bean定義進去,或者替換掉第三方類,就可以在這里將第三方的刪掉,把我們自己的類的bean定義注冊進去。
比如這個就是將以前包里面的實現類換掉,替換成自己新的實現。這個是因為公司的以前的公共包里面封裝了很多公共的東西。然后新的服務要求時間類型用java8.然而公司以前的那個包里面用的不是java8的時間。如果不要用以前封裝的包,很多功能全部都需要重新寫。
因此就通過這個方式,把原來包中的實現換成了新的。
至此整個bean定義的注冊就完成了。
10。最后就是beanFactory的處理器,也是按照先執行容器已經實例化好的,然后是實現PriorityOrdered和Ordered接口的,最后是其他的
這里也可以實現自己的bean工廠后置處理器BeanFactoryPostProcessor,不過這里不能添加或者刪除了,只能修改bean定義的屬性了。比如設置某個bean為懶加載
至此整個bean定義的注冊流程就結束了,invokeBeanFactoryPostProcessors這個方法核心流程也分析完畢了。
關鍵入口流程圖如下: