書接上文,上文書說到invokeBeanFactoryPostProcessors()方法,這個方法十分重要,也至關複雜,咱們繼續分析。spring
首先看下在執行完invokeBeanFactoryPostProcessors()方法以後,容器中發生了哪些變化:post
上面框起來的部分就是執行這個方法以後容器中數據的變化,也就能初步知道這個方法作了什麼了。這個方法主要是解析啓動時構造方法傳入的掃描類(在這個實例中是App.class),看這個類中是否存在@ComponentScan中,若是存在就會去掃描這個註解中配置的須要掃描的包路徑下面的類,被掃描的包下面的類中包含@Component註解的類會將注入到容器中。也就發生了上面圖中的變化。這個就是這個方法主要作的事情。this
上面咱們初步知道了這個方法所作的事情,那麼咱們經過代碼來看下spring是如何處理的。spa
下面咱們就來一點點分析PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors()方法。3d
獲取到的以下beanName:component
這個名字是否是有點熟悉呢?沒錯,它就是在咱們以前說過的初始化AnnotatedBeanDefinitionReader實例的時候所注入的內置處理器ConfigurationClassPostProcessor。對象
beanFactory.getBeanNamesForType()方法具體處理邏輯咱們在後續博文中會詳細說明。blog
咱們繼續看本方法。獲取到postProcessorNames[]以後,會調用getBean()方法取出其bean的實例,add到currentRegistryProcessors和processedBeans集合中。排序
其就是執行了每一個處理器類的postProcessBeanDefinitionRegistry()方法,這裏只處理ConfigurationClassPostProcessor類的這個方法。這個方法很複雜,咱們看下具體實現:接口
首先會從容器中取出全部bean,而後取出類上存在@Configuration、@Component、@ComponentScan、@Import、@ImportResource註解的的bean,add到configCandidates臨時變量中。
其中ConfigurationClassUtils.checkConfigurationClassCandidate()方法處理咱們在以後博文中會詳細解析。
這個方法入參configCandidate其實就是App.class的包裝類型BeanDefinitionHolder。隨後調用其內部的parse方法:
也就是調用processConfigurationClass()方法,這個方法的參數類型是ConfigurationClass,這個類中封裝了元數據信息,資源描述,bean名字。下面咱們就看下processConfigurationClass()方法,這個方法中asSourceClass()和doProcessConfigurationClass()是比較重要的。
asSourceClass():
看上面的代碼很清楚,這個方法就是獲取App.class的註解並循環處理,咱們App.class上的註解就一個@ComponentScan,而後會調用validateAnnotation()方法,這個方法會經過反射機制調用ComponentScan註解類裏定義的方法,以下:具體驗證了什麼還不懂。
最後asSourceClass方法會將App.class封裝成SourceClass對象返回。
下面看下prase()方法,這個方法主要是處理App.class的@ComponentScan註解的方法配置值,有則取出,沒有則設置默認值,包括includeFilters、excludeFilters、lazyInit、basePackage等,取出其中最重要的一行代碼以下:
scanner是ClassPathBeanDefinitionScanner類型對象,咱們看下這行代碼作了什麼?
主要是循環處理@ComponentScan裏配置的包路徑,也就是basePackages。其中上圖紅框中的兩個方法是主要的處理方法:
findCandidateComponents()方法主要是取出當前包內全部包含@Component註解的類。
registerBeanDefinition()方法就是調用了DefaultListableBeanFactory類的registerBeanDefinition()方法,如下是這個方法的片斷:
這個方法在第一節已經說明了,你們應該很熟悉了,就是將掃描出來的beanClass注入到bean工廠中(beanDefinitionMap和beanDefinitionNames)。以上就是本節開始說的容器中發生變化的處理邏輯,也就是爲何註解了@Component的類能注入到bean工廠的緣由了。
上面我只說明了doProcessConfigurationClass()方法中的一個重要的處理邏輯(掃描須要掃描的包下全部須要注入到容器中的bean,完成注入),可是doProcessConfigurationClass()方法中還有一些重要的處理邏輯,好比對註解了@Import、@ImportSource等的beanClass是如何處理的,對beanClass中存在的內部類是如何處理的,等等這些內容是咱們下一節重點說明的。想知道spring是如何處理這部份內容的,請關注我下一篇關於spring的博文。