Spring原始碼解析之BeanFactoryPostProcessor(三)

北洛發表於2021-08-05

在上一章中筆者介紹了refresh()的<1>處是如何獲取beanFactory物件,下面我們要來學習refresh()方法的<2>處是如何呼叫invokeBeanFactoryPostProcessors方法執行bean工廠後置處理器,這個方法在筆者看來是整個refresh()方法最重要的方法之一,因為就是在這個方法完成了掃描類路徑下所有的類,並將類解析成BeanDefinition註冊到spring容器中。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	……
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			……
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//<1>
			……
			try {
				……
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);//<2>
				……
			}

			catch (BeansException ex) {
				……
			}

			finally {
				……
			}
		}
	}
	……
}

  

在瞭解invokeBeanFactoryPostProcessors(beanFactory)方法的運作原理前,我們需要對spring的兩個介面有一個基本的認識:BeanFactoryPostProcessor(bean工廠後置處理器)、BeanDefinitionRegistryPostProcessor(bean定義註冊後置處理器)。

public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

  

如果有看過筆者先前寫的Spring原始碼解析之BeanFactoryPostProcessor(一)應該對BeanFactoryPostProcessor有印象,在這一章節中筆者說過BeanFactoryPostProcessor介面實現類的執行時機是在掃描完所有BeanDefinition並註冊到spring容器之後,以及例項化bean之前。這一章筆者也建立了一個BeanFactoryPostProcessor介面的實現類Test1BeanFactoryPostProcessor,在postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法中筆者將userService的beanDefinition的class替換成OrderService.class,當我們從spring容器獲取userService對應的bean,bean的型別為OrderService而不是UserService。

那麼筆者不禁有個疑問,spring又是如何根據程式設計師指定的類路徑將路徑下的類解析成BeanDefinition並註冊進spring容器呢?答案就在BeanDefinitionRegistryPostProcessor。根據spring官方文件介紹:BeanDefinitionRegistryPostProcessor介面的作用就是向spring容器註冊BeanDefinition,且BeanDefinitionRegistryPostProcessor的執行時機在BeanFactoryPostProcessor之前,而BeanFactoryPostProcessor的作用更傾向於在spring容器獲取到所有BeanDefinition後,在例項化bean之前,修改BeanDefinition的屬性。比如設定連線池的最大連線數不能超過1000,我們就可以在BeanFactoryPostProcessor獲取連線池BeanDefinition的最大連線數,如果超過一千則將最大連線數改為1000。又或者我們提供了一個聊天服務介面ChatService,並實現了一個與之同名的實現類,假設這個實現類是基於MySQL實現的一個聊天服務,後續我們又開發了一個基於Redis的聊天服務實現類ChatService2,當外部需要依賴注入ChatService介面時我們更希望注入的是基於Redis實現的ChatService2聊天服務而不是原先基於MySQL實現的ChatService,也可以實現一個BeanFactoryPostProcessor,並將chatService的BeanDefinition的class替換成ChatService2。

Spring原始碼解析之BeanFactoryPostProcessor(一)講述AnnotatedBeanDefinitionReader的時候,筆者曾說過這個類的構造方法會執行到AnnotationConfigUtils.registerAnnotationConfigProcessors(...),在這個方法內會註冊一些基礎元件的BeanDefinition註冊進spring容器中。當時筆者說過其中一個基礎元件:ConfigurationClassPostProcessor就是完成BeanDefinition掃描的工作,而ConfigurationClassPostProcessor這個類就實現了BeanDefinitionRegistryPostProcessor,在postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法中掃描出配置類指定路徑下所有的類,並篩選出那些可以成為BeanDefinition的類註冊到spring容器中。

此外,BeanDefinitionRegistryPostProcessor的父類是BeanFactoryPostProcessor,從某個角度上來看:BeanDefinitionRegistryPostProcessor介面的實現也可以看作是BeanFactoryPostProcessor。因此refresh()方法中呼叫的invokeBeanFactoryPostProcessors(beanFactory),除了執行BeanFactoryPostProcessor的實現類,還會執行BeanDefinitionRegistryPostProcessor的實現類,而且BeanDefinitionRegistryPostProcessor實現類的執行時機會先於BeanFactoryPostProcessor的實現類。

當呼叫invokeBeanFactoryPostProcessors(beanFactory)方法時,會進而執行到PostProcessorRegistrationDelegate類的靜態方法invokeBeanFactoryPostProcessors(...),這個方法接收一個beanFactory和BeanFactoryPostProcessor列表。

在下面的程式碼<1>處,會先判斷傳入的beanFactory物件能否轉型成BeanDefinitionRegistry,在Spring原始碼解析之BeanFactoryPostProcessor(二)章節中筆者曾介紹這針對註解(AnnotationConfigApplicationContext)和XML(ClassPathXmlApplicationContext)應用上下文spring各開發了兩個父類GenericApplicationContext和AbstractRefreshableApplicationContext來獲取beanFactory,這兩個父類的beanFactory物件型別為DefaultListableBeanFactory,DefaultListableBeanFactory類既是ConfigurableListableBeanFactory介面的實現類,也是BeanDefinitionRegistry介面的實現類,所以大部分情況下會進入<1>處的分支。因為通常我們啟動spring容器不是通過註解就是通過XML初始化應用上下文,而註解和XML應用上下文返回的beanFactory型別實際上都是DefaultListableBeanFactory,除非是重寫refreshBeanFactory()、獲取getBeanFactory()這兩個方法,那麼可以自定義一個BeanFactory的實現類且不實現ConfigurableListableBeanFactory介面,也就不會進到分支<1>。

在進入到<1>處的分支後會迴圈beanFactoryPostProcessors列表,如果列表內的元素可以轉型成BeanDefinitionRegistryPostProcessor,則執行元素實現的的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,將元素新增到registryProcessors列表,如果不能轉型則新增到regularPostProcessors列表,到達一定時機,spring會執行registryProcessors和regularPostProcessors兩個列表中元素實現的postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)。這裡也印證了spring官方文件所說的BeanDefinitionRegistryPostProcessor實現類會優先於BeanFactoryPostProcessor實現類執行。

此外,這裡我們也注意到引數beanFactoryPostProcessors是由AbstractApplicationContext呼叫getBeanFactoryPostProcessors()方法傳入的,getBeanFactoryPostProcessors()會返回beanFactoryPostProcessors這個列表,beanFactoryPostProcessors預設為一個空列表,我們可以呼叫addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)將自己建立的bean工廠後置處理器物件新增到beanFactoryPostProcessors這個列表。因此,在執行invokeBeanFactoryPostProcessors(...)最初會先執行由程式設計師建立的BeanDefinitionRegistryPostProcessor物件。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	……
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
	……
	@Override
	public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
		Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
		this.beanFactoryPostProcessors.add(postProcessor);
	}
	public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
		return this.beanFactoryPostProcessors;
	}
	……
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
		……
	}
	……
}

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();
		
		if (beanFactory instanceof BeanDefinitionRegistry) {//<1>
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}
			……
		}
		
		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}
		……
	}
	……
}

  

這裡我們建立一個bean工廠後置處理器(BeanFactoryPostProcessor)和BeanDefinition註冊後置處理器(BeanDefinitionRegistryPostProcessor)的實現類,並建立者兩個類的例項新增到上下文物件然後看看兩個實現類實現的介面的回撥時機。

Test3BeanDefinitionRegistryPostProcessor.java

package org.example.beanFactoryPostProcessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class Test2BeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("test2 postProcessBeanFactory...");
    }
}

 

Test3BeanDefinitionRegistryPostProcessor.java 

package org.example.beanFactoryPostProcessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

public class Test3BeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("test3 postProcessBeanDefinitionRegistry...");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("test3 postProcessBeanFactory...");
    }
}

  

測試用例:

    @Test
    public void test05() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        ac.addBeanFactoryPostProcessor(new Test2BeanFactoryPostProcessor());
        ac.addBeanFactoryPostProcessor(new Test3BeanDefinitionRegistryPostProcessor());
        ac.refresh();
    }

  

列印結果:

test3 postProcessBeanDefinitionRegistry...
test3 postProcessBeanFactory...
test2 postProcessBeanFactory...

  

可以看到spring會優先執行BeanDefinitionRegistryPostProcessor實現類的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,再執行BeanDefinitionRegistryPostProcessor實現類的postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,最後才執行BeanFactoryPostProcessor實現類的postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法。

需要注意一點的是:spring有兩種提供bean工廠後置處理器(BeanFactoryPostProcessor )的方式:

  1. 建立一個bean工廠後置處理器物件並呼叫addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)將物件新增到spring容器中供spring回撥。
  2. 編寫一個BeanFactoryPostProcessor的實現類,並且給類標記上@Component註解,spring會獲取實現了BeanFactoryPostProcessor介面的類,並生成bean呼叫其介面,比如前面筆者所編寫的Test1BeanFactoryPostProcessor。

這兩種方式不同點是:前者是程式設計師手動建立bean工廠後置處理器物件再交由spring執行,但這個物件本身不是一個bean,這個物件雖然實現了spring的介面,但它的生命週期不歸spring管理;後者是bean工廠後置處理器物件的建立由spring負責,這個物件在spring容器中是一個bean,spring同樣會這個bean的回撥方法,這個bean的生命週期由spring管理。

上面這兩種提供方式同樣適用於BeanDefinition註冊後置處理器(BeanDefinitionRegistryPostProcessor),因為BeanDefinitionRegistryPostProcessor本身就可以看成是一個BeanDefinitionRegistryPostProcessor。

標記了@Component註解的BeanFactoryPostProcessor實現類,它的bean物件不在AbstractApplicationContext類的beanFactoryPostProcessors列表中。換句話說beanFactoryPostProcessors列表的元素必須手動建立物件並新增,假設我們開發了兩個BeanDefinitionRegistryPostProcessor的實現類:FooBeanDefinitionRegistryPostProcessor和BarBeanDefinitionRegistryPostProcessor,FooBeanDefinitionRegistryPostProcessor是用過手動建立物件新增到beanFactoryPostProcessors列表,BarBeanDefinitionRegistryPostProcessor是通過@Component註解由spring建立bean物件。下面程式碼<1>處遍歷beanFactoryPostProcessors列表中只有一個FooBeanDefinitionRegistryPostProcessor物件會得到執行,而BarBeanDefinitionRegistryPostProcessor對應的bean會在後面的程式碼進行介面回撥,但不會在<1>處進行回撥。

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();
		
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {//<1>
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}
			……
		}
		……
	}
	……
}

  

我們來對比下下面18~29、32~42這兩段程式碼,這兩段程式碼完成的工作是極其相似的,會遍歷所有已經註冊到spring容器的BeanDefinition,找出BeanDefinitionRegistryPostProcessor實現類對應的beanName並將其返回。之後會在<1>、<2>處判斷這個beanName對應的class在實現了BeanDefinitionRegistryPostProcessor介面的前提下,是否分別實現了PriorityOrdered、Ordered介面。

Ordered是PriorityOrdered的父介面,PriorityOrdered本身並沒有實現任何方法,而是直接繼承Ordered,實現了PriorityOrdered的類會優先於實現了Ordered的類執行。Ordered介面會要求實現類返回一個數值用於排序,返回數值越小的實現類排在越前。之後這兩段程式碼都會從bean工廠根據beanName和型別獲取BeanDefinitionRegistryPostProcessor實現類的bean物件,並將待執行的bean物件加到currentRegistryProcessors列表,將對應的beanName加入到processedBeans表示已經處理這個bean,再對currentRegistryProcessors列表進行排序,這裡就會用到Ordered介面要求返回的數值,越小排越前,即返回數值越小越優先執行。

排序完畢後會將currentRegistryProcessors列表的元素加入到registryProcessors列表,然後呼叫invokeBeanDefinitionRegistryPostProcessors(...)方法遍歷currentRegistryProcessors列表每個物件,執行其實現的postProcessBeanDefinitionRegistry(...)方法,開始真正處理列表中每一個bean物件,處理完畢後再清空currentRegistryProcessors列表。而registryProcessors列表在未來的某個時機,會執行列表中所有物件實現的postProcessBeanFactory(...)方法。

需要注意一點:第一段程式碼會找出所有實現了BeanDefinitionRegistryPostProcessor和PriorityOrdered介面的實現類,將其beanName加入到processedBeans表示這個bean已經處理,即便這個時候尚未執行bean物件的postProcessBeanDefinitionRegistry(...)方法,但後續會執行。第二段程式碼在找出BeanDefinitionRegistryPostProcessor和Ordered介面實現類的同事,也會找到第一段程式碼已經找到的實現類,因為PriorityOrdered是Ordered的子介面,意味著實現了PriorityOrdered同樣實現了Ordered,但這裡不會出現重複執行同一個bean物件的的postProcessBeanDefinitionRegistry(...)方法,因為在第二段程式碼會再判斷beanName是否在processedBeans中,只有不在processedBeans集合的beanName才允許執行,如果beanName已經在processedBeans,表明這個bean在之前已經執行了postProcessBeanDefinitionRegistry(...)方法。currentRegistryProcessors列表在這兩段程式碼都只會存放尚未執行的BeanDefinitionRegistryPostProcessor實現類,並且在這兩段程式碼執行完畢後都會清空currentRegistryProcessors列表,所以我們也不用擔心registryProcessors列表會存在相同的bean物件。

這裡還可以和大家先劇透一下,先前我們介紹的在構造AnnotatedBeanDefinitionReader物件時會將一些基礎元件以BeanDefinition的形式註冊到spring容器中待後續spring容器根據BeanDefinition構造bean,其中一個基礎元件ConfigurationClassPostProcessor就會在下面第一段程式碼(即18~29行)執行,ConfigurationClassPostProcessor為BeanDefinitionRegistryPostProcessor和PriorityOrdered兩個介面的實現類,在執行這個實現類的postProcessBeanDefinitionRegistry(...)方法時,就會掃描配置類指定的類路徑,並篩選類路徑下可以成為BeanDefinition的類註冊進spring容器,供後續spring根據BeanDefinition構造bean。ConfigurationClassPostProcessor是如何完成BeanDefinition的篩選和註冊後續筆者還會講解,這裡我們只要知道第一段程式碼會完成類路徑的掃描即可。

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
			
		// Invoke BeanDefinitionRegistryPostProcessors first, if any.	
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			……
			// 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.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//<1>
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
			
			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {//<2>
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
			……
		}
		……
	}
	……
}

  

BeanDefinitionRegistryPostProcessor介面是spring較為底層的介面,spring-context包下也只有ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor介面,除了ConfigurationClassPostProcessor類之外spring家族再無BeanDefinitionRegistryPostProcessor介面的實現。此外就筆者目前所見的開源框架,除了spring-context、spring-boot外,也只有mybatis整合spring的包(mybatis-spring)實現了BeanDefinitionRegistryPostProcessor介面,即:org.mybatis.spring.mapper.MapperScannerConfigurer,不過MapperScannerConfigurer類並沒有實現PriorityOrdered和Ordered的介面,所以MapperScannerConfigurer並不會再上面的程式碼執行,而是會在後續的某個時機執行。

在先後執行完實現了PriorityOrdered和Ordered介面的BeanDefinitionRegistryPostProcessor實現類,會用一個while迴圈不斷從bean工廠獲取尚未執行的BeanDefinitionRegistryPostProcessor實現類,因為可能存在spring在執行一個BeanDefinitionRegistryPostProcessor實現類的postProcessBeanDefinitionRegistry(...)方法時有新的BeanDefinitionRegistryPostProcessor類以BeanDefinition的形式註冊進bean工廠。每次迴圈都會把尚未執行的BeanDefinitionRegistryPostProcessor實現類加入到registryProcessors列表,直到獲取不到尚未執行的BeanDefinitionRegistryPostProcessor實現類才會退出迴圈,而我們之前所說的MapperScannerConfigurer類也就是在下面的while迴圈執行的,退出while迴圈後統一執行registryProcessors和regularPostProcessors列表中物件實現的postProcessBeanFactory(...)。

已經找到整個專案中所有的BeanDefinitionRegistryPostProcessor物件,這個列表的順序會優先儲存程式設計師手動建立的BeanDefinitionRegistryPostProcessor物件,再儲存實現了PriorityOrdered和Ordered介面的BeanDefinitionRegistryPostProcessor物件,,不管是內建的亦或是整合別的專案或是程式設計師自己開發的BeanDefinitionRegistryPostProcessor實現類,都會存到,和regularPostProcessors兩個列表中物件實現的postProcessBeanFactory(...)方法。

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
			
		// Invoke BeanDefinitionRegistryPostProcessors first, if any.	
		Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) { …… // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. boolean reiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } …… } …… }

  

如果beanFactory可以轉型成BeanDefinitionRegistry,則會進入分支<1>,而在分支<1>內部會做的工作我們也已經瞭解。如果beanFactory不能轉型成BeanDefinitionRegistry,則會進入分支<2>,這裡就會執行我們手動建立的BeanFactoryPostProcessor物件的postProcessBeanFactory(...)方法。但就筆者目前的開發經驗,大部分情況下都會進入分支<1>,會進入分支<2>的情況筆者至今還未見過,希望有這方面業務經驗的同學可以不吝賜教。

在執行分支<1>或分支<2>的程式碼後,會獲取spring容器內所有BeanFactoryPostProcessor實現類對應的beanName,這裡依舊可能把之前已經處理過的beanName獲取出來。在遍歷這些beanName的時候如果判斷已經在processedBeans集合中,則表示已經處理過,這裡就會跳過這個beanName,如果是不在processedBeans集合,則會根據是否實現PriorityOrdered、Ordered介面和都沒實現分為三組,會分別對實現了PriorityOrdered和Ordered介面的bean工廠處理器進行排序,再分組執行,最後執行沒有實現PriorityOrdered和Ordered介面的bean工廠後置處理器。

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
			
		// Invoke BeanDefinitionRegistryPostProcessors first, if any.	
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {//<1>
			……
		}
		
		else {//<2>
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 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<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		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(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		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();
	}
	……
}

  

下面我們來看看PriorityOrdered和Ordered兩個介面,正如筆者所言, PriorityOrdered介面本身並沒有要求實現任何方法,PriorityOrdered介面的設計只是為了和Ordered做一個區分,子介面會優先執行,父介面會在子介面執行完畢後才執行。這兩個介面都會要求實現類在getOrder()方法返回一個數值,數值越小排序越前。

public interface PriorityOrdered extends Ordered {
}

public interface Ordered {

	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

	int getOrder();

}

  

最後,我們總結下PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(...)整個方法的流程就結束本章的講解。這個方法接收一個beanFactory物件,和beanFactoryPostProcessors列表。通常情況下:beanFactoryPostProcessors列表是程式設計師手動建立的BeanFactoryPostProcessor物件,beanFactory可以轉型成BeanDefinitionRegistry,所以會進入下面程式碼<1>處的分支。在分支<1>內部會建立兩個列表regularPostProcessors和registryProcessors,這裡會遍歷beanFactoryPostProcessors列表,判斷列表中每個物件是否能轉型成BeanDefinitionRegistryPostProcessor介面,如果轉型成功則執行其實現的postProcessBeanDefinitionRegistry(...)方法並將物件存放到registryProcessors列表,轉型失敗則存放在regularPostProcessors列表。

之後在程式碼的33~44行會獲取已經以BeanDefinition形式存放到spring容器內BeanDefinitionRegistryPostProcessor實現類對應的beanName,並判斷beanName對應的BeanDefinitionRegistryPostProcessor實現類是否也實現了PriorityOrdered,實現了PriorityOrdered介面則會進入<2>處的分支,從bean工廠根據beanName獲取對應的bean物件並加入到currentRegistryProcessors列表,之後會將currentRegistryProcessors列表進行排序,將列表中的元素新增到registryProcessors,執行currentRegistryProcessors列表所有物件實現的postProcessBeanDefinitionRegistry(...)方法,再清空currentRegistryProcessors列表。而在33~44行也會執行BeanDefinitionRegistryPostProcessor的實現類ConfigurationClassPostProcessor,在這個實現類的postProcessBeanDefinitionRegistry(...)方法中完成類路徑的掃描,解析類路徑下可以成為BeanDefinition的類並將其註冊到spring容器中。

程式碼47~57行和33~44太過相似,不同的是後者執行的是同樣實現了Ordered介面的BeanDefinitionRegistryPostProcessor實現類,由於PriorityOrdered是Ordered的子介面,這裡會把33~44行已經執行過的beanName找出來,但這些已經執行過的beanName已經存放在processedBeans集合,所以這裡會過濾掉,只會執行尚未執行的Ordered和BeanDefinitionRegistryPostProcessor的實現類。

在程式碼<4>處會有一個while迴圈,不斷去遍歷spring容器內現有BeanDefinitionRegistryPostProcessor實現類對應的beanName,這裡同樣會把之前已經找到的beanName獲取出來,同樣會用processedBeans集合過濾已經處理過的beanName,只會執行尚未執行的BeanDefinitionRegistryPostProcessor實現類的bean物件。等到確定spring容器內不再有尚未執行的BeanDefinitionRegistryPostProcessor實現類就會退出while迴圈。此時registryProcessors已經擁有了程式設計師手動建立的BeanDefinitionRegistryPostProcessor物件和整個spring容器所有的BeanDefinitionRegistryPostProcessor實現類的bean物件,在<5>處會執行這些BeanDefinitionRegistryPostProcessor物件的postProcessBeanFactory(...)方法,再執行程式設計師手動建立的BeanFactoryPostProcessor物件的postProcessBeanFactory(...)方法,至此完成分支<1>的所有工作,所有的BeanDefinitionRegistryPostProcessor物件都先後完成了postProcessBeanDefinitionRegistry(...)和postProcessBeanFactory(...)方法的呼叫。

之後會獲取spring容器內所有BeanFactoryPostProcessor實現類對應的beanName,這裡會遍歷這些beanName,如果已經存在processedBeans集合的beanName代表已經處理過,這裡會跳過已經處理過的beanName,收集實現了PriorityOrdered或Ordered介面,和這兩個介面都沒實現的BeanFactoryPostProcessor實現類的bean物件,這裡會優先對實現了PriorityOrdered介面的BeanFactoryPostProcessor物件進行排序並執行postProcessBeanFactory(...)方法,再對實現了Ordered介面的BeanFactoryPostProcessor物件進行排序再執行postProcessBeanFactory(...)方法,最後是執行沒有實現PriorityOrdered或Ordered介面的BeanFactoryPostProcessor物件的postProcessBeanFactory(...)方法。

這裡也再次證實了spring對BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor兩個介面的定義:BeanDefinitionRegistryPostProcessor的實現會優先於BeanFactoryPostProcessor執行,而BeanDefinitionRegistryPostProcessor實現的postProcessBeanDefinitionRegistry(...)也會優先本身實現的postProcessBeanFactory(...)執行,最後才執行僅實現了BeanFactoryPostProcessor介面的postProcessBeanFactory(...)方法。

final class PostProcessorRegistrationDelegate {
	……
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {//<1>
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				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.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//<2>
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {//<3>
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {//<4>
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//<5>
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 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<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		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(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		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();
	}
	……
}

  

 

相關文章