springboot原始碼之(bean的遞迴註冊)
在prepareContext中,用loader呼叫load方法,loader是 BeanDefinitionLoader,在BeanDefinitionLoader的構造方法中,
會例項化一個AnnotatedBeanDefinitionReader,在reader的構造方法中,
有一個靜態方法registerAnnotationConfigProcessors,裡面註冊一個ConfigurationClassPostProcessor,
實現了BeanDefinitionRegistryPostProcessor進而實現了BeanFactoryPostProcessor。
而applicationContext在refresh的時候,呼叫invokeBeanFactoryPostProcessors(beanFactory);
在該方法裡,呼叫了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors這個靜態方法,
這裡面取出所有的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,並呼叫兩個介面的方法,但是最終都是呼叫
processConfigBeanDefinitions方法,先取出當前工廠中的beanDefinitions(一般除了系統自己的一些indicator,就是run方法中傳入的object陣列的內容,一般就是一個啟動類),
並不是所有的這些初始的beanDefinitions都會被解析
判斷的邏輯是:
1、是否有@Import,@Component,@ImportSource,@ComponentScan之一
2、再判斷裡面是否有@Bean方法。
這個邏輯也很好理解,因為如果這五個註解都沒有,那麼基本上也就不是一個想引入其他bean的configuration類。
進入候選之後,PostProcessor生成parser,解析候選,而接下來所有的五個註解解析出來的beanDefinition,包括從內部類,和父類中一共七個通道,
不用再判斷是否含有這五個註解,這是因為解析的邏輯也是尋找這五個註解,無非就是麻煩一點。
@Import的解析邏輯,對於被import進來的每一個類:
分四種情況:
1、實現了ImportSelector介面的,且 實現了其子介面 DeferredImportSelector的,先放進一個list,在parse方法執行完之後,遍歷list,取出其中的selector,呼叫
import方法, 返回String[]陣列,遍歷陣列,呼叫processImports方法重新解析import(再走一遍1234)
2、實現了ImportSelector介面的,但沒有實現其子介面 DeferredImportSelector的,直接呼叫import方法,遞迴呼叫processImports方法(也就是再走一遍1234)
3、實現了ImportBeanDefinitionRegistrar介面的,新增到一個list中,在後來的reader的loadBeanDefinitions中呼叫registerBeanDefinitions方法向工廠中註冊bean
4、如果以上都不是,當做配置類解析上面的五個註解。
@ComponentScan註解的解析比較簡單,看看包裡面所有的類,根據filter(預設的有兩個過濾器,過濾@
如果為空,預設是類當前所在的資料夾(ClassUtils.getPackageName)。載入,解析五個註解。
@PropertySource是解析配置檔案
@ImportResource是匯入xml檔案?
@Bean是生成一個factoryBeanMethod,例項化的時候反射呼叫@Bean的方法