spring源碼(四)——@Configuration到底幹了什麼

前言

上篇博客基本梳理了一下@Configuration註解的類註冊源碼上的一些細節和流程。

一個實例

準備三個類,一個配置類,兩個普通類,其中一個普通類可以什麼都不做

@Component
public class TestBean {
    //這個普通類裏面只有一個構造方法
    public TestBean() {
        System.out.println("this is testBean one constructor method");
    }
}
/**
 * autor:liman
 * createtime:2020/4/6
 * comment:
 */
public class TestBean02 {

}

配置類

@Configuration
@ComponentScan(value="com.learn.importselector.config")
public class AppConfig {
    
    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
    
    @Bean
    public TestBean02 testBean02(){
        testBean();//這裏也會調用testBean方法。
        return new TestBean02();
    }
}

問題:TestBean的構造方法會被調用幾次?注意在TestBean02中也會調用testBean方法。

引入一個測試代碼

public class TestOutOfConfig {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext
                = new AnnotationConfigApplicationContext(AppConfig.class);

        TestBean02 testBean = annotationConfigApplicationContext.getBean(TestBean02.class);
    }
}

答案:如果加上了@Configuration,則只會調用一次,如果去掉@Configuration註解則會調用兩次

運行情況:

加入了@Configuration註解後的運行情況

在這裏插入圖片描述

取消@Configuration註解後的運行情況

在這裏插入圖片描述

問題:@Configuration到底幹了啥?爲啥去掉@Configuration之後會調用兩次?

CGLIB代理的簡單實例

其實之前總結過代理,這裏還是想說一下CGLIB的代理,因爲後面的源碼閱讀會用到

一個目標類

/**
 * autor:liman
 * createtime:2020/4/11
 * comment:
 */
public class HelloService {
	public HelloService(){
		System.out.println("this is construct method of HelloService");
	}
    //這個方法不會被代理,因爲是final方法
	final public String sayOthers(String name){
		System.out.println("hello service to others : "+name);
		return null;
	}
	public void sayHello(){
		System.out.println("helloService:sayHello");
	}
}

一個方法調用攔截器

public class SelfMethodInterceptor implements MethodInterceptor {

	/**
	 *
	 * @param o 目標對象
	 * @param method 目標方法
	 * @param objects 目標方法參數
	 * @param methodProxy 目標方法的代理類 methodProxy.invokeSuper()
	 * @return
	 * @throws Throwable
	 */
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("self interceptor before");
		System.out.println(method.getName());//sayHello()
		methodProxy.invokeSuper(o,objects);
		System.out.println(methodProxy.getClass().getSimpleName());
		System.out.println(methodProxy.getSignature());//代理後的方法
		System.out.println("self interceptor after");
		return null;
	}
}

調用的實例

/**
 * autor:liman
 * createtime:2020/4/11
 * comment:這裏需要引入CGLIB的調用包
 */
public class CglibTest {

	public static void main(String[] args) {
//將生成的代理類導入到指定文件夾,可以查看CGLIB生成的代理類的class源碼
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\cglib_class");
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(HelloService.class);
		enhancer.setCallback(new SelfMethodInterceptor());
		HelloService proxy = (HelloService) enhancer.create();
		proxy.sayHello();
	}

}

依舊是個前提

我們這篇博客是要總結@Configuration這個註解spring底層到底幹了什麼,這裏我們就從上篇博客的後續開始,還是貼入我們討論了很多次的方法

//TODO :PostProcessorRegistrationDelegate中的第56行
public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
    //TODO: 定義一個容器,表示已經處理過了的BeanFactoryPostProcessor
	Set<String> processedBeans = new HashSet<>();

	//TODO:如果BeanFactory是一個註冊器(這個好像必會進入)
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

		//TODO:這裏定義了兩個集合,一個是BeanFactoryPostProcessor,一個是BeanDefinitionRegistryPostProcessor
		//TODO:放自定義的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		//TODO:BeanDefinitionRegistryPostProcessor只是繼承了BeanFactoryPostProcessor接口而已
		//TODO:放自定義的BeanDefinitionRegistryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		//TODO : 遍歷傳入過來的集合beanFactoryPostProcessors
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			//TODO:如果自定義的BeanFactoryPostProcessor實現了BeanDefinitionRegistryPostProcessor接口
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//TODO:如果是BeanDefinitionRegistryPostProcessor
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);//TODO:調用postProcessor其中的方法
				registryProcessors.add(registryProcessor);
			}
			else {//TODO:如果自定義的BeanFactoryPostProcessor沒有實現現BeanDefinitionRegistryPostProcessor接口
				regularPostProcessors.add(postProcessor); //TODO:將自定義的BeanFactoryProcessor放到上面定義的集合中
			}
		}

		// 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.
		//TODO:又定義一個集合存放BeanDefinitionRegistryPostProcessor,這個集合存放的是spring內部實現了這個接口的類
		//TODO:放spring內部定義的BeanDefinitionRegistryPostProcessor
		//TODO:每次真正調用的,纔是這個集合中的BeanDefinitionRegistryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		//TODO:根據bean的類型獲取bean的名稱,這裏獲取的是BeanDefinitionRegistryPostProcessor類型的
		//TODO:首先調用實現了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
		//TODO:根據Type獲取對應類型的beanName,這裏纔會獲取出內部定義的ConfigurationClassPostProcessor
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		//TODO:遍歷上面獲得的postProcessorNames,並根據每個beanName獲取對應的beanDefinition,然後放到currentRegistryProcessors中
		//TODO:如果沒有自定義的,則這個時候這裏就一個
		//TODO:同時將遍歷的每一個beanName放到processedBeans中
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				//TODO:將 ConfigurationClassPostProcessor 標記爲已經處理
				processedBeans.add(ppName);
			}
		}
		//TODO:設置排序,不重要
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		//TODO:合併兩個集合,將spring自定義的Processors加入到registryProcessors中,可以看到所謂的currentRegistryProcessors就是一個過渡的
		registryProcessors.addAll(currentRegistryProcessors);
		//TODO:真正的開始調用BeanDefinitionRegistryPostProcessor中的方法
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		//TODO:清空currentRegistryProcessors,這裏就清除了 ConfigurationClassPostProcessor
		currentRegistryProcessors.clear();

		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		//TODO:開始調用實現了Ordered接口的BeanDefinitionRegistryPostProcessor類
		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);
			}
		}
		//TODO:和上面的操作一樣,但是這個時候 currentRegistryProcessors 中只會有實現了Ordered接口的BeanDefinitionRegistryPostProcessor
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		//TODO:最後,調用其他的BeanDefinitionRegistryPostProcessors,直到沒有更多的BeanDefinitionRegistryPostProcessors實現類
		//TODO:簡單點說這裏就是在掃除剩餘的沒被調用的BeanDefinitionRegistryPostProcessors實例
		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.
		//TODO:到這裏,調用postProcessBeanFactory(即BeanDefinitionRegistryPostProcessors的父類)的回調方法,這裏面就有針對@Configuration類的增強操作
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}

	//TODO:如果一個beanFactory不是註冊器,這個應該是一個兼容操作,老版本的spring的BeanFactory是沒有實現Registry接口的
	else {
		// Invoke factory processors registered with the context instance.
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}

	//TODO:開始處理 BeanFactoryProcessor 類型的類,並回調指定的方法(就是隻實現了BeanFactoryPorcessor接口的類)
	// 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.
	//TODO:如果已經在processedBeans集合中,這裏不再做處理
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();//TODO:存放實現了 PriorityOrdered 接口的 BeanFactoryProcessor
	List<String> orderedPostProcessorNames = new ArrayList<>(); //TODO:存放實現了 Ordered 接口的 BeanFactoryProcessor
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();//TODO:存放沒有實現 Ordered 接口也沒有實現 PriorityOrdered 的 BeanFactoryProcessor
	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);
		}
	}

	//TODO:調用實現了PriorityOrdered接口的BeanFactoryPostProcessor回調方法
	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	//TODO:調用實現了Ordered接口的 BeanFactoryPostProcessors 回調方法
	// 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.
	//TODO:最後,處理兩個接口爲沒有實現的正常的 BeanFactoryPostProcessors 回調方法
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	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();
}

這裏再次總結一下spring中回調BeanFactoryPostProcessor接口實現類的方法,就是上面這段代碼,invokeBeanFactoryPostProcessors方法。

這個方法在AbstractApplicationContext類中被調用的時候,傳入進來的是這樣的

//TODO:通過委託對象調用指定的BeanFactoryPostProcessor(這裏是調用自定義的BeanFactoryPostProcessor)
//TODO:這裏的getBeanFactoryPostProcessors()並不是取出spring內部定義的BeanFactoryPostProcessor,而是取出程序員自己定義的BeanFactoryPostProcessor
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

這裏只需記住一點,通過getBeanFactoryPostProcessors()得到的是我們自己定義的BeanFactoryPostProcessor 。前面我們說過,BeanFactoryPostProcessor其實還有一個子接口BeanDefinitionRegistryPostProcessor源碼如下所示

/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

接口BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的基礎上擴展了一個方法。這也就意味着BeanDefinitionRegistryPostProcessor接口有兩個方法。我們看看spring是怎麼處理的(其實關於spring如何調用BeanFactoryPostProcessor後置處理的,在上面整個方法的代碼中,已經通過註解給出了)。下面一段段解構上述方法。首先說明一下,在invokeBeanFactoryPostProcessors方法中,spring爲了兼容原來老版本的操作,做了一個if判斷,判斷如果BeanFactory是BeanDefinitionRegistry的話就進入一個if語句塊,如果不是,就走else分支。這裏我們從if語句塊開始。

1、先處理自定義的BeanFactoryPostProcessor

//TODO:如果BeanFactory是一個註冊器(這個好像必會進入)
if (beanFactory instanceof BeanDefinitionRegistry) {
	BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

	//TODO:這裏定義了兩個集合,一個是BeanFactoryPostProcessor,一個是BeanDefinitionRegistryPostProcessor
	//TODO:放自定義的BeanFactoryPostProcessor
	List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
	//TODO:BeanDefinitionRegistryPostProcessor只是繼承了BeanFactoryPostProcessor接口而已
	//TODO:放自定義的BeanDefinitionRegistryPostProcessor
	List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

	//TODO : 遍歷傳入過來的集合beanFactoryPostProcessors
	for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
		//TODO:如果自定義的BeanFactoryPostProcessor實現了BeanDefinitionRegistryPostProcessor接口
		if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//TODO:如果是BeanDefinitionRegistryPostProcessor
			BeanDefinitionRegistryPostProcessor registryProcessor =
					(BeanDefinitionRegistryPostProcessor) postProcessor;
			registryProcessor.postProcessBeanDefinitionRegistry(registry);//TODO:調用postProcessor其中的方法
			registryProcessors.add(registryProcessor);
		}
		else {//TODO:如果自定義的BeanFactoryPostProcessor沒有實現現BeanDefinitionRegistryPostProcessor接口
			regularPostProcessors.add(postProcessor); //TODO:將自定義的BeanFactoryProcessor放到上面定義的集合中
		}
	}
	
	//............暫時省略後面的代碼
}

我們說過,通過參數傳遞進來的beanFactoryPostProcessors是我們自己定義的beanFactoryPostProcessors,可以很明顯的看到,如果我們定義的beanFactoryPostProcessors實現了BeanDefinitionRegistryPostProcessor接口,則會被先處理,然後放入registryProcessors集合中,如果只實現了BeanFactoryPostProcessor接口,則會放入regularPostProcessors集合中

2、開始處理spring內部實現了BeanDefinitionRegistryPostProcessor接口的實現類。

之後我們接着往下看

// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
//TODO:又定義一個集合存放BeanDefinitionRegistryPostProcessor,這個集合存放的是spring內部實現了這個接口的類
//TODO:放spring內部定義的BeanDefinitionRegistryPostProcessor
//TODO:每次真正調用的,纔是這個集合中的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//TODO:根據bean的類型獲取bean的名稱,這裏獲取的是BeanDefinitionRegistryPostProcessor類型的
//TODO:首先調用實現了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
//TODO:根據Type獲取對應類型的beanName,這裏纔會獲取出內部定義的ConfigurationClassPostProcessor
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//TODO:遍歷上面獲得的postProcessorNames,並根據每個beanName獲取對應的beanDefinition,然後放到currentRegistryProcessors中
//TODO:如果沒有自定義的,則這個時候這裏就一個
//TODO:同時將遍歷的每一個beanName放到processedBeans中
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		//TODO:將 ConfigurationClassPostProcessor 標記爲已經處理
		processedBeans.add(ppName);
	}
}
//TODO:設置排序,不重要
sortPostProcessors(currentRegistryProcessors, beanFactory);
//TODO:合併兩個集合,將spring自定義的Processors加入到registryProcessors中,可以看到所謂的currentRegistryProcessors就是一個過渡的
registryProcessors.addAll(currentRegistryProcessors);
//TODO:真正的開始調用BeanDefinitionRegistryPostProcessor中的方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//TODO:清空currentRegistryProcessors,這裏就清除了 ConfigurationClassPostProcessor
currentRegistryProcessors.clear();

我們發現又定義了一個currentRegistryProcessors集合,這個集合其實就是用來存放待處理的BeanFactoryPostProcessor實現類。

通過如下這一句,spring獲得了內部自動創建的,並且實現了BeanDefinitionRegistryPostProcessor接口的實現類。之前我們討論過,在spring初始化過程中,會爲我們自動創建六個重要的對象,這六個重要的對象中,有一個就實現了這個接口,這個就是ConfigurationClassPostProcessor

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

通過這一句代碼,spring就獲取了創建的ConfigurationClassPostProcessor對象。

我們可以看到處理的代碼很簡單,只是將這個對象放入currentRegistryProcessors集合中,並在invokeBeanDefinitionRegistryPostProcessors執行之後,就清空了currentRegistryProcessors集合,其中invokeBeanDefinitionRegistryPostProcessors底部就是完成ConfigurationClassPostProcessor對象中postProcessBeanDefinitionRegistry方法的回調,這個方法中就完成了包的掃描和beanDefinition的註冊。

3、之後,調用實現了Ordered接口的BeanDefinitionRegistryPostProcessor和還沒有被調用的BeanDefinitionRegistryPostProcessor對象。這個不太重要,但是套路都是一個

// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//TODO:開始調用實現了Ordered接口的 BeanDefinitionRegistryPostProcessor 類
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);
	}
}
//TODO:和上面的操作一樣,但是這個時候 currentRegistryProcessors 中只會有實現了Ordered接口的BeanDefinitionRegistryPostProcessor
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//TODO:最後,調用其他的BeanDefinitionRegistryPostProcessors,直到沒有更多的BeanDefinitionRegistryPostProcessors實現類
//TODO:簡單點說這裏就是在掃除剩餘的沒被調用的BeanDefinitionRegistryPostProcessors實例
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();
}

4、之後回調BeanFactoryPostProcessor對象中的postProcessBeanFactory方法

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//TODO:到這裏,調用postProcessBeanFactory(即BeanDefinitionRegistryPostProcessors的父類)的回調方法,這裏面就有針對@Configuration類的增強操作
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

後面的代碼大同小異,只是針對spring框架中內部實現了BeanFactoryPostProcessor接口的類,整個方法梳理到這裏,我們至少可以得出一個結論。在這個比較複雜的方法中,spring是先處理的BeanDefinitionRegistryPostProcessor的回調,再處理的BeanFactoryPostProcessor的回調(或者你會說廢話)但是接下來的東西就比較重要了,我們說過spring內部定義的一個類ConfigurationClassPostProcessor即實現了BeanDefinitionRegistryPostProcessor接口,也實現了BeanFactoryPostProcessor接口,那麼根據我們剛纔得出的結論,我們就可以得出,spring是先回調ConfigurationClassPostProcessor類中的postProcessBeanDefinitionRegistry方法,再回調ConfigurationClassPostProcessor類中的postProcessBeanFactory方法。

上一篇博客中,我們詳細介紹了spring回調ConfigurationClassPostProcessor類中的postProcessBeanDefinitionRegistry方法的操作,spring就是在這個方法底層完成了掃描和@Import註解的處理,同時也標記出了@Configuration類,這個方法的回調工作就完成了。但是我們開頭說了,針對@Configuration標記的類,可不簡單的標記掃描註冊就完事,至少還要有個代理。至少要避免我們開頭那種操作(調用兩次實例化方法的操作)

@Configuration的面紗

從 ConfigurationClassPostProcessor 回調postProcessBeanFactory方法說起。

/**
 * TODO:ConfigurationClassPostProcessor第243行
 * TODO:這裏會完成對@Configuration的增強處理
 * Prepare the Configuration classes for servicing bean requests at runtime
 * by replacing them with CGLIB-enhanced subclasses.
 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	int factoryId = System.identityHashCode(beanFactory);
	if (this.factoriesPostProcessed.contains(factoryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
	}
	this.factoriesPostProcessed.add(factoryId);
	if (!this.registriesPostProcessed.contains(factoryId)) {
		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
		// Simply call processConfigurationClasses lazily at this point then.
        //如果配置類沒有註冊的話,完成一次註冊
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}

	//TODO:對@Configuration實現增強處理
	enhanceConfigurationClasses(beanFactory);
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

於是我們發現有個enhanceConfigurationClasses的方法,enhance就是增強的意思。說明spring底層對@Configuration標記的類進行了一個增強。繼續進入

/**
 * TODO:onfigurationClassPostProcessor 第338行
 * TODO:對@Configuration進行增強處理
 * Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
 * any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
 * Candidate status is determined by BeanDefinition attribute metadata.
 * @see ConfigurationClassEnhancer
 */
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		//TODO://是否是一個全代理的類(是否加了@Configuration)
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
			if (!(beanDef instanceof AbstractBeanDefinition)) {
				throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
						beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
			}
			else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
				logger.info("Cannot enhance @Configuration bean definition '" + beanName +
						"' since its singleton instance has been created too early. The typical cause " +
						"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
						"return type: Consider declaring such methods as 'static'.");
			}
			//TODO:如果加了@Configuration 則放入configBeanDefs集合中
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	if (configBeanDefs.isEmpty()) {
		// nothing to enhance -> return immediately
		return;
	}

	//TODO:對@Configuration的類進行增強
	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
		AbstractBeanDefinition beanDef = entry.getValue();
		// If a @Configuration class gets proxied, always proxy the target class
		beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		try {
			// Set enhanced subclass of the user-specified bean class
			Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
			if (configClass != null) {
				//TODO:進行增強
				Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
				if (configClass != enhancedClass) {
					if (logger.isTraceEnabled()) {
						logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
								"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
					}
					beanDef.setBeanClass(enhancedClass);
				}
			}
		}
		catch (Throwable ex) {
			throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
		}
	}
}

可以看到這個方法比較簡單,也就是遍歷了BeanDefinition的名字,然後通過名字取出指定的BeanDefinition ,判斷這個BeanDefinition是否是@Configuration標記的類,如果是則放入configBeanDefs集合中。之後遍歷這個集合對每一個@Configuration進行代理操作。所以核心就是下面這一行

Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);

繼續往下

/**
 * TODO:ConfigurationClassEnhancer中的第97行
 * Loads the specified class and generates a CGLIB subclass of it equipped with
 * container-aware callbacks capable of respecting scoping and other bean semantics.
 * @return the enhanced subclass
 */
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
	if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
		if (logger.isDebugEnabled()) {
			logger.debug(String.format("Ignoring request to enhance %s as it has " +
					"already been enhanced. This usually indicates that more than one " +
					"ConfigurationClassPostProcessor has been registered (e.g. via " +
					"<context:annotation-config>). This is harmless, but you may " +
					"want check your configuration and remove one CCPP if possible",
					configClass.getName()));
		}
		return configClass;
	}
	//TODO:利用CGLIB創建增強類,newEnhancer完成具體的增強屬性的設置
	Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
	if (logger.isTraceEnabled()) {
		logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
				configClass.getName(), enhancedClass.getName()));
	}
	return enhancedClass;
}

通過spring本身的英文註釋就能看出,這是一個通過CGLIB生成代理子類的方法(這也就是我爲啥要在開頭列出一個CGLIB的實例的原因),如果不熟悉CGLIB的就看文章開頭的那個實例。

之後進入到createClass中的newEnhancer方法中

/**
 * TODO:ConfigurationClassEnhancer第122行
 * TODO:創建一個基於CGLIB的增強類
 * Creates a new CGLIB {@link Enhancer} instance.
 */
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
	Enhancer enhancer = new Enhancer();
	//TODO:將當前配置了設置成父類
	enhancer.setSuperclass(configSuperClass);
	//TODO:讓代理類實現EnhancedConfiguration接口,這個接口繼承了BeanFactoryAware接口,可讓我們的代理類獲得BeanFactory便於重新註冊相關bean
	enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);//TODO:代理類的產生不利用工廠模式
	//TODO:命名策略
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	//TODO:設置CGLIB的生成策略
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	//TODO:設置最終代理類的回調攔截器
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	//TODO:返回生成的代理類
	return enhancer;
}

文章開頭的那個實例中說過,CGLIB的代理的增強邏輯主要就在攔截器中,我們看到, enhancer.setCallbackFilter(CALLBACK_FILTER);這個不就是設置代理的邏輯麼,繼續進入

// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
		new BeanMethodInterceptor(),
		new BeanFactoryAwareMethodInterceptor(),
		NoOp.INSTANCE
};

private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

發現給@Configuration標記的類主要的代理邏輯就在BeanMethodInterceptorBeanFactoryAwareMethodInterceptor中重點看這兩個類中的intercept方法即可

BeanMethodInterceptor

這個主要就是針對調用@Configuration標記的類中的@Bean方法的攔截操作

/**
 * TODO:針對@Bean方法的增強
 * Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
 * existence of this bean object.
 * @throws Throwable as a catch-all for any exception that may be thrown when invoking the
 * super implementation of the proxied method i.e., the actual {@code @Bean} method
 */
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
			MethodProxy cglibMethodProxy) throws Throwable {

	//TODO:獲取beanFactory容器
	ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
	String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

	// Determine whether this bean is a scoped-proxy
	if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
		String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
		if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
			beanName = scopedBeanName;
		}
	}

	// To handle the case of an inter-bean method reference, we must explicitly check the
	// container for already cached instances.

	// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
	// proxy that intercepts calls to getObject() and returns any cached bean instance.
	// This ensures that the semantics of calling a FactoryBean from within @Bean methods
	// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
	//TODO:處理@Bean方法返回FactroyBean的情況
	/**
	 * TODO:首先,檢查@Bean方法返回的是否是一個FactoryBean,如果是,則創建一個返回的FactoryBean的代理類
	 * TODO:底層調用FactoryBean中的getObject方法,然後返回這個對象。
	 */
	if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
			factoryContainsBean(beanFactory, beanName)) {
		Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
		if (factoryBean instanceof ScopedProxyFactoryBean) {
			// Scoped proxy factory beans are a special case and should not be further proxied
		}
		else {
			//TODO:針對BeanFactory的增強操作,並調用getObject方法
			// It is a candidate FactoryBean - go ahead with enhancement
			return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
		}
	}

    //TODO:針對普通的bean的處理
	//TODO:爲了避免出現嵌套調用的問題 isCurrentlyInvokedFactoryMethod
	if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
		// The factory is calling the bean method in order to instantiate and register the bean
		// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
		// create the bean instance.
		if (logger.isInfoEnabled() &&
				BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
							"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
							"result in a failure to process annotations such as @Autowired, " +
							"@Resource and @PostConstruct within the method's declaring " +
							"@Configuration class. Add the 'static' modifier to this method to avoid " +
							"these container lifecycle issues; see @Bean javadoc for complete details.",
					beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
		}
		//TODO:調用@Configuration類中的目標方法
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}

	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

整體來看這個方法分爲三個分支,針對web操作中,@Bean註解的方法返回的bean是否是一個域級的代理;@Bean註解的方法返回的bean是否是一個FactoryBean;以及@Bean註解的方法返回的bean是一個普通的bean,如何避免被重複調用的問題,都有處理

其中isCurrentlyInvokedFactoryMethod這個判斷方法就是爲了避免我們開頭實例中兩次執行的情況。

BeanFactoryAwareMethodInterceptor

這個是針對如果這個配置類實現了BeanFactoryAware接口的攔截操作

@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
	Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
	Assert.state(field != null, "Unable to find generated BeanFactory field");
	field.set(obj, args[0]);

	// Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
	// If so, call its setBeanFactory() method. If not, just exit.
	if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
		return proxy.invokeSuper(obj, args);
	}
	return null;
}

這個方法就簡單的多。只是一個簡單的判斷,之後直接調用

總結

整篇博客預熱較久,但是針對@Configuration與@ComponentScan和@Import等註解有何區別,這裏似乎可以有個結論了:@Configuration標記的類在spring中會被將對應的BeanDefinition屬性configurationClass標記爲FULL,而其他的則會將BeanDefinition屬性configurationClass標記爲lite(中文爲:部分)。另一個最大的區別就是加上了@Configuration註解的類,spring底層會用CGLIB對這個類做一個代理,而其他註解則不會。這就是@Configuration最特殊的地方,也是最牛逼的地方。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章