寫在最前
上篇文章 - 詳解Spring的ImportSelector接口(1) http://www.lxweimin.com/p/aa99a303bc37中,我們最后留下了兩個疑問。今天我們先說說第一個疑問 - ImportSelector是如何被Spring框架調用的呢?
ImportSelector是如何被Spring框架調用的呢?
ClassPathXmlApplicationContext
我們以ClassPathXmlApplicationContext為例子,看看Spring在啟動過程中是如何調用到ImportSelector接口的。
如上圖,我們初始化一個ClassPathXmlApplicationContext時需要指定一個xml文件作為應用上下文。該構造器中又調用了另一個構造器,我們跟進去看下:
從上面的代碼中,我們可以看到在設置完configLocations后調用了refresh()方法。那么,refresh()方法又是干什么的呢?
AbstractApplicationContext的refresh()方法
refresh()定義在ConfigurableApplicationContext接口中,具體的實現在AbstractApplicationContext中,如下:
從上面的實現中,我們可以看到該方法做了很多準備、初始化、事件通知等工作。具體的我們就不一一看了,今天我們只關心其中的
invokeBeanFactoryPostProcessors
方法。
從上面的代碼中我們可以看到,invokeBeanFactoryPostProcessors()方法把具體的調用方法委托給了
PostProcessorRegistrationDelegate
類。另外,從該方法的名字當中我們也可以看出,該方法主要的目的是:實例化,并調用BeanFactoryPostProcessor類的。BeanFactoryPostProcessor是一個接口,有很多的實現類,這里我們就暫且不管BeanFactoryPostProcessor的具體用處了。我們先進入PostProcessorRegistrationDelegate
一窺究竟。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(xxx)方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 如果有BeanDefinitionRegistryPostProcessors 的話,就先調用它們
// 處理過的Beans
Set<String> processedBeans = new HashSet<String>();
// 是否是BeanDefinitionRegistry類型的BeanFactory. BeanDefinitionRegistry的作用是可以用來注冊,刪除,獲取BeanDefinitions
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 普通類型的BeanFactoryPostProcessor集合
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
// BeanDefinitionRegistry類型的BeanFactoryPostProcessor集合(BeanDefinitionRegistryPostProcessor繼承于BeanFactoryPostProcessor)
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
new LinkedList<BeanDefinitionRegistryPostProcessor>();
// 對集合beanFactoryPostProcessors進行分類,如果是BeanDefinitionRegistry類型的BeanFactoryPostProcessor;則調用方法 - postProcessBeanDefinitionRegistry()。、、
// postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)該方法的作用是在標準的BeanDefinitions初始化完成后可以修改容器上下文內部的beanDefinition。
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryPostProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
registryPostProcessors.add(registryPostProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 這里不要初始化FactoryBeans,我們需要保留這些普通的beans 不在這里初始化,目的是為了讓bean factory post-processor去處理他們。
// 根據BeanDefinitionRegistryPostProcessors 實現的不同接口,拆分開來去調用他們。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先,調用實現了優先級接口 - PriorityOrdered的BeanDefinitionRegistryPostProcessors
List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 添加排序好的優先級PostProcessors到registryPostProcessors集合
registryPostProcessors.addAll(priorityOrderedPostProcessors);
// 調用排序好的優先級BeanDefinitionRegistryPostProcessors,postProcessBeanDefinitionRegistry方法會被調用,用來修改,獲取,刪除容器上下文中的bean定義。
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 調用實現了Ordered接口的BeanDefinitionRegistryPostProcessors ,大致邏輯同上PriorityOrdered的處理
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
registryPostProcessors.addAll(orderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 調用所有其它類型的BeanDefinitionRegistryPostProcessors
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
registryPostProcessors.add(pp);
processedBeans.add(ppName);
pp.postProcessBeanDefinitionRegistry(registry);
reiterate = true;
}
}
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
// 調用所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory 方法。
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
// 調用容器中BeanFactoryPostProcessor類型的bean(不包含BeanDefinitionRegistryPostProcessor類型的beans)。
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
// 若beanFactory不是BeanDefinitionRegistry類型的,則直接調用容器中所有的BeanFactoryPostProcessor的postProcessBeanFactory 方法。
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 下面是BeanFactoryPostProcessor的具體調用過程,和上面的過程很相似,這里就不多說了。
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(beanFactory, orderedPostProcessors);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
上面的調用關系中,我們可以看出。在這個方法中有兩種類型的PostPorcessor被調用處理了;而這兩種PostProcessor的關系如下圖:
BeanDefinitionRegistryPostProcessor繼承于BeanFactoryPostProcessor。我們大致看看接口定義的方法:
postProcessBeanFactory用于在標準的初始化完成后修改容器上下文中的beanFactory。所有bean定義將被加載,但是它們將暫時不被實例化,這允許覆蓋,甚至添加一些屬性到延遲初始化的bean上。
postProcessBeanDefinitionRegistry方法在標準化初始化完成后可以修改容器內部的bean definition registry。所有的常規的bean定義都將被加載,但是沒有bean被實例化。這允許我們在下一個處理階段增加一些新的bean定義。
綜合上面的邏輯,postProcessBeanDefinitionRegistry是在postProcessBeanFactory方法之前被調用的。
ConfigurationClassPostProcessor
上面說了這么多,目的是為了說明我們的主角 - ConfigurationClassPostProcessor。ConfigurationClassPostProcessor類實現了BeanDefinitionRegistryPostProcessor接口,同時還實現了一些其他的接口,如下圖:
ConfigurationClassPostProcessor類實現了父類的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法,如下圖:
由上面的分析可知,postProcessBeanDefinitionRegistry方法的調用早于postProcessBeanFactory方法。所有我們先來看看postProcessBeanDefinitionRegistry方法的具體內容:
從注釋中我們可以看到,這個方法的主要作用是進一步從配置中獲取bean的定義,也就是被@Configuration注解修飾的配置類。該方法中又調用了processConfigBeanDefinitions()方法,該方法主要用于處理@Configuration注解。
在processConfigBeanDefinitions方法中又調用了ConfigurationClassParser類的parse方法用于解析@Configuration,如下圖:
我們在進入到ConfigurationClassParser類的parse方法看看,如下:
看到這里,我們終于看見曙光了,終于看見DeferredImportSelector接口了。我們忽略方法中其它部分代碼,直接進入到processDeferredImportSelectors()方法一窺究竟。
processDeferredImportSelectors方法中調用了processImports方法執行導入,跟進去看看,在processImports 方法中有很重要的一段代碼,如下:
如上圖中代碼所示:
- 檢查類型是否是ImportSelector,如果是則執行第2步。
- 如果同時實現了Aware接口和ImportSelector接口,則先調用Aware接口的實現方法;然后進入第三步。
- 調用selector的selectImpors方法,把要導入的類的元數據信息作為參數,根據具體的實現邏輯返回要導入的classes。
- 執行后續的代碼...
說到這里,我們可以看到ImportSelector接口的實現方法selectImports終于被調用成功了。
總結
- ImportSelector的導入實現是通過BeanFactoryPostProcessor接口的子接口BeanDefinitionRegistryPostProcessor來實現的。
- ImportSelector接口的處理是伴隨著@Configuration注解的處理一起處理的。
- ImportSelector接口可以實現自定義條件選擇性導入classes。
- ImportSelector接口的字接口DeferredImportSelector在所有@Configuration處理完成后才被處理的。
- 處理ImportSelector接口時,bean定義已經被加載,但是bean還沒有被實例化。
- Spring Bootn的自動配置功能就是通過DeferredImportSelector接口的實現類EnableAutoConfigurationImportSelector做到的。