Spring原始碼分析-BeanFactoryPostProcessor

Jame!發表於2021-10-31

Spring原始碼分析-BeanFactoryPostProcessor

博主技術有限,本文難免有錯誤的地方,如果您發現了歡迎評論私信指出,謝謝

BeanFactoryPostProcessor介面是Spring提供的對Bean的擴充套件點,它的子介面是BeanDefinitionRegistryPostProcessor

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


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

BeanFactoryPostProcessor簡單使用

BeanFactoryPostProcessor的執行時機是在Spring掃描完成後,Bean初始化前,當我們實現BeanFactoryPostProcessor介面,可以在Bean的初始化之前對Bean進行屬性的修改

@Component
public class A {
}

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition("a");
		beanDefinition.setScope("prototype");
	}
}

@Configuration
@ComponentScan("com.jame")
public class Myconfig {
}

public class MyTest {
	public static void main(String[] args)  {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
		A a = context.getBean(A.class);
		A a1 = context.getBean(A.class);
		System.out.println(a==a1);
    }
}

輸出結果為:false

上面的例子我們將A的BeanDefinition的scope設定為原型,預設沒有設定scope的情況下bean的scope都是單例,也就是說我們成功的修改了A物件的beanDefinition,能修改的屬性不止這一個,還有是否懶載入,初始化方法名稱,設定屬性等等

而它的子類BeanDefinitionRegistryPostProcessor可以對spring容器中的BeanDefinition進行操作

不瞭解BeanDefinition的可以先簡單理解為包裝Java類的一個類,例如我們給類設定的是否單例,是否懶載入這些資訊都需要儲存,而spring就建立一個BeanDefinition,用來儲存除了java類以外的其他資訊

BeanDefinitionRegistryPostProcessor簡單使用

@Component
public class A {
}

public class B  {
}

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(B.class);
		registry.registerBeanDefinition("b",beanDefinition);
		registry.removeBeanDefinition("a");
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}
}

@Configuration
@ComponentScan("com.jame")
public class Myconfig {
}

public class MyTest {
	public static void main(String[] args)  {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
		B b = context.getBean(B.class);
		System.out.println(b);
		A a = context.getBean(A.class);
    }
}

輸出結果:

com.jame.pojo.B@2ac1fdc4
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.jame.pojo.A' available......

上面的程式碼中我們對A類加上了@Component,B類什麼都沒有加,結果應該是A獲取到正常輸出,然後獲取B時報錯找不到,但是結果恰恰相反,因為我們在MyBeanDefinitionRegistryPostProcessor類中對Spring管理的Bean進行了修改,新增了一個B的BeanDefinition,刪除了A的BeanDefinition,所以結果就如上面呈現的那樣

完成了上面的簡單使用案例接下來就開始看Spring的執行原理是什麼

原始碼分析

首先第一步要知道什麼時候執行的上面的程式碼,為了方便就不將查詢過程貼上出來了,可以在實現類中輸出句話,Debug看看是在那個方法中輸出的

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   this();
   register(componentClasses);
   refresh();
}

進入refresh方法

@Override
public void refresh() throws BeansException, IllegalStateException {
......
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
........
}
}

進入invokeBeanFactoryPostProcessors方法

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

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

			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
            
			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();
			}

			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		} else {
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
                
			} 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);
			}
		}

		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
		beanFactory.clearMetadataCache();
	}

來看最上面定義

Set<String> processedBeans = new HashSet<>();

這個也很好理解,存放已經執行完的BeanFactoryPostProcessor名字,防止重複執行

if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

			//存放直接實現BeanFactoryPostProcessor,處理過/找到的實現類
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();

			//存放直接實現BeanDefinitionRegistryPostProcessor,處理過/找到的實現類
			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);
				}
			}

來看第一個if判斷,判斷傳入的BeanFactory是否是BeanDefinitionRegistry型別,大部分情況都是,我們先預設它一直為true

那麼上面定義兩個集合用來存放已經處理過的實現類

下面這個for迴圈只有通過api來設定的BeanFactoryPostProcessor才會有值,什麼意思呢?看下面

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());

為什麼沒有呢?因為我們的程式碼執行順序的問題,來看上面的使用程式碼,是先new AnnotationConfigApplicationContext(MyConfig.class)

而在它的構造中就已經呼叫refresh->invokeBeanFactoryPostProcessors->invokeBeanFactoryPostProcessors方法了

而我們debug時候還沒有走到context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());方法,所以為空

那怎麼使用?我們仔細來看AnnotationConfigApplicationContext的構造

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();   
    register(componentClasses);    
    refresh();
}

裡面就3個方法,調自己無參,register,refresh,而執行invokeBeanFactoryPostProcessors在refresh方法中,也就是說我們可以在refresh方法前進行註冊即可

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Myconfig.class);
    context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    context.refresh();

這樣,我們就能在refresh方法前進行手動呼叫api的方式新增

繼續往下

if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    BeanDefinitionRegistryPostProcessor registryProcessor =
        (BeanDefinitionRegistryPostProcessor) postProcessor;
    registryProcessor.postProcessBeanDefinitionRegistry(registry);
    registryProcessors.add(registryProcessor);
} else {
    regularPostProcessors.add(postProcessor);
}

判斷是BeanDefinitionRegistryPostProcessor型別,如果是,則直接執行.否則新增到集合,還記得這個集合嗎在最外層的if中

if (beanFactory instanceof BeanDefinitionRegistry) {
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    //存放直接實現BeanFactoryPostProcessor,處理過/找到的實現類
    List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();

    //存放直接實現BeanDefinitionRegistryPostProcessor,處理過/找到的實現類
    List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    ......
}

如果不是則新增到regularPostProcessors集合,為什麼這個型別不執行因為和Spring的執行順序有關,等到最後在說

從List currentRegistryProcessors = new ArrayList<>();建立這個集合開始向下看

List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

首先這個集合幹啥的:用來存放當前需要執行的BeanDefinitionRegistryPostProcessor

存放需要執行的BeanDefinitionRegistryPostProcessor的好理解,那什麼叫做當前的?? 提前說一下,這個集合是在下面複用的,當前的就是當前正在執行的BeanDefinitionRegistryPostProcessor型別是一類的,先往下看,一會再解釋

首先它建立一個字串陣列來接收beanFactory.getBeanNamesForType的返回引數,簡單說下這個方法的作用

從BeanDefinitionNames中尋找型別為傳入型別的BeanDefinition的名稱

呼叫鏈為:DefaultListableBeanFactory.getBeanNamesForType->DefaultListableBeanFactory.doGetBeanNamesForType,有興趣可以自己去看看

那我們debug來看看獲取到型別是BeanDefinitionRegistryPostProcessor的beanName都有誰

那麼繼續向下

if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) 檢查傳入的PostProcessorName的BenaDefinition是否符合PriorityOrdered.class,當然該方法的作用不止於此,我們現在只分析有關的

PriorityOrdered是一個排序的介面,它的父類是Ordered,誰的值越小越先呼叫,先簡單瞭解下即可,不是本章重點

public interface PriorityOrdered extends Ordered {
}


public interface Ordered {
	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
	int getOrder();
}

留個疑問,這個BeanDefinition什麼時候進來的?先繼續看程式碼整體返回true進入判斷

currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

主要重點在getBean方法,以後有機會在單獨寫篇getBean的,簡單理解為從Spring的容器中獲取類,如果不存在則從BeanDefinitionMap中找到對應BeanDefinition,然後例項化返回

那麼假設我們已經獲取到了例項化後的java物件,它是誰呢?debug

請記住這個類 ConfigurationClassPostProcessor

之後將當前類的名稱存放到已經處理過的set中,在該方法的最上面

//儲存已經完成處理的BeanFactoryPostProcessor名字
Set<String> processedBeans = new HashSet<>();

之後呼叫排序方法,然後把已經處理過的BeanFactoryPostProcessor存放到List

//存放直接實現BeanDefinitionRegistryPostProcessor,處理過的實現類
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

我們重點來看invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);方法

private static void invokeBeanDefinitionRegistryPostProcessors(
    Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}

上面找到的ConfigurationClassPostProcessor是重中之重,Spring的掃描就是這個類中完成的,何以證明?Debug

我們來看beanFactory中的BeanDefinitionMap數量即可

關於Spring的掃描以後有機會寫一篇

然後清空當前正在執行的List集合,繼續向下

postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    //這裡判斷如果在儲存已經完成的集合中沒有找到當前的BeanDefinitionRegistryPostProcessor
    //也就是說明這個還沒有被執行過,那麼放入當前執行的集合中進行下一步操作
    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//一樣的程式碼,執行postProcessBeanFactory方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

發現了什麼,程式碼和上面的很像,那麼我們不在贅述,直接簡單說一下重點

if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) 

判斷除了已經處理過的,防止重複執行,然後就是判斷型別,上面的型別是PriorityOrdered 現在是Ordered

那麼再來看

 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

而這個集合就是剛才定義的存放"當前處理"的集合

List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

什麼叫當前處理,在最開始執行的時候,這個集合存放的都是實現PriorityOrdered介面的類,對於上面來說,"當前處理的"就是實現PriotyOrdered類,然後程式碼執行到currentRegistryProcessors.clear();那麼對於實現PriorityOrdered介面的類來說,"當前處理"的這個集合,已經不是存放PriorityOrdered介面的實現類了

而到了這裡,這個list中只存放Ordered型別的,那麼"當前處理的"就指的是實現Ordered介面的類,因為它這個集合是好多地方複用的,所以叫做"當前處理"集合

那麼下面的程式碼應該能看明白吧,上面處理了實現PriorityOrdered,Ordered的BeanDefinitionRegistryPostProcessor,都執行完了最後執行沒有實現兩者的BeanDefinitionRegistryPostProcessor

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();
}

那麼這裡可能有個疑問

registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

這不是執行過了嗎,為啥還要放集合,請注意,當前找的介面是BeanDefinitionRegistryPostProcessor的實現類,而不是BeanFactoryPostProcessor,那麼一個簡單的java基礎問題,一個類實現了A介面,而A介面又繼承B介面,請問這個類需要實現B介面定義的方法嗎,答案是肯定的,那麼上面的只是執行BeanDefinitionRegistryPostProcessor介面中定義的方法,所以來看後兩行就一目瞭然了

//為什麼要傳入已經執行過的BeanDefinitionRegisterPostProcess的集合?
//因為我們自定義的類實現了BeanDefinitionRegisterPostProcess這個介面
//而這個介面又繼承了BeanFactoryPostProcess,那麼我們不僅要實現子類的方法,還要實現父類的方法
//而在上面的處理僅僅呼叫了子類的方法,所以又在這裡呼叫一次父類的方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

好的,到此為止,使用Api新增的PostProcessor完成,但是有個小問題,發現了嗎,每次postProcessorNames都是重新獲取一次,為什麼不獲取一次然後一直使用呢?

回過頭我們來看開始使用BeanDefinitionRegistryPostProcessor的簡單使用案例,假設實現PriorityOrdered介面的類在呼叫完postProcessBeanDefinitionRegistry方法對bean的數量進行了修改,那麼下面的操作獲取的資料都不是最新的,為了解決這個問題所以每次操作都重新獲取一遍

繼續向下走,下面的程式碼就是我們通過掃描或xml找到的BeanFactoryPostProcessor實現類

String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//分別是存放實現了priorityOrdered介面,Ordered介面,和沒有實現Ordered介面的名稱集合
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<>();
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<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
    nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);



下面的程式碼就比較簡單了,就簡單寫下

首先還是通過 beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);獲取型別為BeanFactoryPostProcessor的實現類名稱,然後依次判斷實現了PriorityOrdered介面了嗎,實現Ordered介面了嗎,還是兩個都沒實現

分別放到對應的集合中,隨後順序執行

我們來捋一下執行的順序

  1. 通過Api新增實現BeanDefinitionRegistryPostProcessor的類
  2. Spring內建
    1. 實現PriorityOrdered介面
    2. 實現Ordered介面
    3. 兩者都沒實現
  3. 通過Api新增實現BeanFactoryPostProcessor的類
  4. 執行通過掃描/xml配置實現BeanFactoryPostProcessor和PriorityOrdered的類
  5. 執行通過掃描/xml配置實現BeanFactoryPostProcessor和Ordered的類
  6. 執行通過掃描/xml配置實現BeanFactoryPostProcessor的類

我們來寫程式碼實際演示下

整體結構如下

@Component
public class BDPP implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("俺啥排序介面都沒實現");
    }
}


@Component
public class BDPPOrdered0 implements Ordered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 0;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("實現Ordered的BDPP,排序0");
    }
}

@Component
public class BDPPOrdered1 implements Ordered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 1;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("實現Ordered的BDPP,排序1");
    }
}


@Component
public class BDPPPriorityOrdered0 implements PriorityOrdered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 0;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("實現PriorityOrdered的BDPP,排序0");
    }
}

@Component
public class BDPPPriorityOrdered1 implements PriorityOrdered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 1;}

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("實現PriorityOrdered的BDPP,排序1");
    }
}


public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("Api新增的BeanDefinitionRegistryPostProcessor,我是該介面的方法");
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Api新增的BeanDefinitionRegistryPostProcessor,我是父介面方法");
    }
}


public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Api新增的BeanFactoryPostProcessor");
    }
}


public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Myconfig.class);
    context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    context.addBeanFactoryPostProcessor(new MyBeanDefinitionRegistryPostProcessor());
    context.refresh();
}

在Spring掃描的方法中新增一句話用於輸出

其他Spring內建的就不再去新增了,我們來看結果

也就是說如果想在Spring完成掃描前對Bean進行一些操作可以實現BeanDefinitionRegistryPostProcessor介面並手動新增,而上面的輸出也顯示了,在同繼承PriorityOrdered或Ordered的時候,值小的先執行

還有一個問題,我們在獲取BeanFactoryPostProcessor時名稱使用前每次都是重新獲取一下,而在下面通過掃描或Xml配置的BeanFactoryPostProcessor時卻只進行一次獲取

String[] postProcessorNames =    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

因為BeanFactoryPostProcessor介面只是對bean進行增強處理,不會進行刪除新增的操作

回答上面的疑問:這個ConfigurationClassPostProcessor的BeanDefinition什麼時候進來的

來看new AnnotationConfigApplicationContext()的無參構造

public AnnotationConfigApplicationContext() {
    //spring內建的bd將在這裡進行註冊
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    //這裡
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    BeanDefinitionRegistry registry, @Nullable Object source) {
    .....
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
    .......
}

還記得上面第一次通過String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

來看CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME這個常量的值是啥

public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
    "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

而它這個if判斷是

@Override
public boolean containsBeanDefinition(String beanName) {
    Assert.notNull(beanName, "Bean name must not be null");
    return this.beanDefinitionMap.containsKey(beanName);
}

也就是說在初始化時,如果不存在則進行註冊beanDefinition,具體註冊的方法從

beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

registry.registerBeanDefinition(beanName, definition);

DefaultListableBeanFactory.registerBeanDefinition註冊beanDefinition的方法,有興趣可以點進去看看

相關文章