這是春節后的第一篇博客,我在構思這篇博客的時候,一度想放棄,想想要不要換個東西寫,因為畢竟個人水平有限,Spring源碼實在博大精深,不是我這個菜的摳腳的菜雞可以駕馭的,怕誤人子弟,還有就是源碼分析類的博客實在是太難寫了,和一般的博客真心不同,可能寫了很多,自己都不知道自己在寫些什么,但是還是要堅持,從接觸博客的那一天開始,就非常佩服那些大神,樂於分享,無私奉獻,我也從那些博客中學到了不少東西,慢慢的從一個嫩嫩的小菜雞變成了禿頭大菜雞,其中最佩服的就是那些源碼分析類的博客,雖然看不懂,但是從博客中,我分明讀出了大神們對技術的熱愛,對技術的堅持,對技術的執著。堅持!
在上一篇Spring源碼解析中,我們分析了
//根據參數類型可以知道,其實可以傳入多個annotatedClasses,但是這種情況出現的比較少
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//調用無參構造函數,會先調用父類GenericApplicationContext的構造函數
//父類的構造函數里面就是初始化DefaultListableBeanFactory,並且賦值給beanFactory
//本類的構造函數里面,初始化了一個讀取器:AnnotatedBeanDefinitionReader read,一個掃描器ClassPathBeanDefinitionScanner scanner
//scanner的用處不是很大,它僅僅是在我們外部手動調用 .scan 等方法才有用,常規方式是不會用到scanner對象的
this();
//把傳入的類進行注冊,這里有兩個情況,
//傳入傳統的配置類
//傳入bean(雖然一般沒有人會這么做
//看到后面會知道spring把傳統的帶上@Configuration的配置類稱之為FULL配置類,不帶@Configuration的稱之為Lite配置類
//但是我們這里先把帶上@Configuration的配置類稱之為傳統配置類,不帶的稱之為普通bean
register(annotatedClasses);
//刷新
refresh();
}
中的前兩行代碼,回顧下,這兩行代碼,主要是把我們的配置類和內置的幾個后置處理器放到了兩個集合中:
//beanDefinitionMap是Map<String, BeanDefinition>,
//這里就是把beanName作為key,beanDefinition作為value,推到map里面
this.beanDefinitionMap.put(beanName, beanDefinition);
//beanDefinitionNames就是一個List<String>,這里就是把beanName放到List中去
this.beanDefinitionNames.add(beanName);
今天,我們來分析下第三行代碼,即:
//刷新
refresh();
這個方法做了很多事情,讓我們點開這個方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新預處理,和主流程關系不大,就是保存了容器的啟動時間,啟動標志等
prepareRefresh();
//DefaultListableBeanFactory
// Tell the subclass to refresh the internal bean factory.
//和主流程關系也不大,最終獲得了DefaultListableBeanFactory,
// DefaultListableBeanFactory實現了ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//還是一些准備工作,添加了兩個后置處理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
//還設置了 忽略自動裝配 和 允許自動裝配 的接口,如果不存在某個bean的時候,spring就自動注冊singleton bean
//還設置了bean表達式解析器 等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//這是一個空方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//執行自定義的BeanFactoryProcessor和內置的BeanFactoryProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 空方法
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
里面有很多小方法,我們今天的目標是分析前五個小方法:
prepareRefresh
從命名來看,就知道這個方法主要做了一些刷新前的准備工作,和主流程關系不大,主要是保存了容器的啟動時間,啟動標志等。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
這個方法和主流程關系也不是很大,可以簡單的認為,就是把beanFactory取出來而已。
prepareBeanFactory
//還是一些准備工作,添加了兩個后置處理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
//還設置了 忽略自動裝配 和 允許自動裝配 的接口,如果不存在某個bean的時候,spring就自動注冊singleton bean
//還設置了bean表達式解析器 等
prepareBeanFactory(beanFactory);
這代碼相比前面兩個就比較重要了,我們需要點進去好好看看,做了什么操作:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());//設置類加載器
//設置bean表達式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//屬性編輯器支持
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
//添加一個后置處理器:ApplicationContextAwareProcessor,此后置處理處理器實現了BeanPostProcessor接口
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//以下接口,忽略自動裝配
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
//以下接口,允許自動裝配,第一個參數是自動裝配的類型,,第二個字段是自動裝配的值
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
//添加一個后置處理器:ApplicationListenerDetector,此后置處理器實現了BeanPostProcessor接口
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//如果沒有注冊過bean名稱為XXX,spring就自己創建一個名稱為XXX的singleton bean
//Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
主要做了如下的操作:
- 設置了一個類加載器
- 設置了bean表達式解析器
- 添加了屬性編輯器的支持
- 添加了一個后置處理器:ApplicationContextAwareProcessor,此后置處理器實現了BeanPostProcessor接口
- 設置了一些忽略自動裝配的接口
- 設置了一些允許自動裝配的接口,並且進行了賦值操作
- 在容器中還沒有XX的bean的時候,幫我們注冊beanName為XX的singleton bean
postProcessBeanFactory(beanFactory)
//這是一個空方法
postProcessBeanFactory(beanFactory);
這是一個空方法,可能以后Spring會進行擴展把。
invokeBeanFactoryPostProcessors(beanFactory)
//執行自定義的BeanFactoryProcessor和內置的BeanFactoryProcessor
invokeBeanFactoryPostProcessors(beanFactory);
重點代碼終於來了,可以說 這句代碼是目前為止最重要,也是內容最多的代碼了,我們有必要好好分析下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//getBeanFactoryPostProcessors真是坑,第一次看到這里的時候,愣住了,總覺得獲得的永遠都是空的集合,掉入坑里,久久無法自拔
//后來才知道spring允許我們手動添加BeanFactoryPostProcessor
//即:annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
讓我們看看第一個小方法的第二個參數:
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
這里獲得的是BeanFactoryPostProcessor,當我看到這里的時候,愣住了,通過IDEA的查找引用功能,我發現這個集合永遠都是空的,根本沒有代碼為這個集合添加數據,很久都沒有想通,后來才知道我們在外部可以手動添加一個后置處理器,而不是交給Spring去掃描,即:
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
只有這樣,這個集合才不會為空,但是應該沒有人這么做吧,當然也有可能是我孤陋寡聞。
讓我們點開invokeBeanFactoryPostProcessors方法:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//beanFactory是DefaultListableBeanFactory,是BeanDefinitionRegistry的實現類,所以肯定滿足if
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//regularPostProcessors 用來存放BeanFactoryPostProcessor,
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//registryProcessors 用來存放BeanDefinitionRegistryPostProcessor
//BeanDefinitionRegistryPostProcessor擴展了BeanFactoryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 循環傳進來的beanFactoryPostProcessors,正常情況下,beanFactoryPostProcessors肯定沒有數據
// 因為beanFactoryPostProcessors是獲得手動添加的,而不是spring掃描的
// 只有手動調用annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX)才會有數據
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// 判斷postProcessor是不是BeanDefinitionRegistryPostProcessor,因為BeanDefinitionRegistryPostProcessor
// 擴展了BeanFactoryPostProcessor,所以這里先要判斷是不是BeanDefinitionRegistryPostProcessor
// 是的話,直接執行postProcessBeanDefinitionRegistry方法,然后把對象裝到registryProcessors里面去
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {//不是的話,就裝到regularPostProcessors
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.
//一個臨時變量,用來裝載BeanDefinitionRegistryPostProcessor
//BeanDefinitionRegistry繼承了PostProcessorBeanFactoryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 獲得實現BeanDefinitionRegistryPostProcessor接口的類的BeanName:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
// 並且裝入數組postProcessorNames,我理解一般情況下,只會找到一個
// 這里又有一個坑,為什么我自己創建了一個實現BeanDefinitionRegistryPostProcessor接口的類,也打上了@Component注解
// 配置類也加上了@Component注解,但是這里卻沒有拿到
// 因為直到這一步,Spring還沒有去掃描,掃描是在ConfigurationClassPostProcessor類中完成的,也就是下面的第一個
// invokeBeanDefinitionRegistryPostProcessors方法
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//獲得ConfigurationClassPostProcessor類,並且放到currentRegistryProcessors
//ConfigurationClassPostProcessor是很重要的一個類,它實現了BeanDefinitionRegistryPostProcessor接口
//BeanDefinitionRegistryPostProcessor接口又實現了BeanFactoryPostProcessor接口
//ConfigurationClassPostProcessor是極其重要的類
//里面執行了掃描Bean,Import,ImportResouce等各種操作
//用來處理配置類(有兩種情況 一種是傳統意義上的配置類,一種是普通的bean)的各種邏輯
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//把name放到processedBeans,后續會根據這個集合來判斷處理器是否已經被執行過了
processedBeans.add(ppName);
}
}
//處理排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//合並Processors,為什么要合並,因為registryProcessors是裝載BeanDefinitionRegistryPostProcessor的
//一開始的時候,spring只會執行BeanDefinitionRegistryPostProcessor獨有的方法
//而不會執行BeanDefinitionRegistryPostProcessor父類的方法,即BeanFactoryProcessor的方法
//所以這里需要把處理器放入一個集合中,后續統一執行父類的方法
registryProcessors.addAll(currentRegistryProcessors);
//可以理解為執行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
//Spring熱插播的體現,像ConfigurationClassPostProcessor就相當於一個組件,Spring很多事情就是交給組件去管理
//如果不想用這個組件,直接把注冊組件的那一步去掉就可以
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//因為currentRegistryProcessors是一個臨時變量,所以需要清除
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 再次根據BeanDefinitionRegistryPostProcessor獲得BeanName,看這個BeanName是否已經被執行過了,有沒有實現Ordered接口
// 如果沒有被執行過,也實現了Ordered接口的話,把對象推送到currentRegistryProcessors,名稱推送到processedBeans
// 如果沒有實現Ordered接口的話,這里不把數據加到currentRegistryProcessors,processedBeans中,后續再做處理
// 這里才可以獲得我們定義的實現了BeanDefinitionRegistryPostProcessor的Bean
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);
//合並Processors
registryProcessors.addAll(currentRegistryProcessors);
//執行我們自定義的BeanDefinitionRegistryPostProcessor
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空臨時變量
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 上面的代碼是執行了實現了Ordered接口的BeanDefinitionRegistryPostProcessor,
// 下面的代碼就是執行沒有實現Ordered接口的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();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//registryProcessors集合裝載BeanDefinitionRegistryPostProcessor
//上面的代碼是執行子類獨有的方法,這里需要再把父類的方法也執行一次
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//regularPostProcessors裝載BeanFactoryPostProcessor,執行BeanFactoryPostProcessor的方法
//但是regularPostProcessors一般情況下,是不會有數據的,只有在外面手動添加BeanFactoryPostProcessor,才會有數據
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!
//找到BeanFactoryPostProcessor實現類的BeanName數組
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<>();
//循環BeanName數組
for (String ppName : postProcessorNames) {
//如果這個Bean被執行過了,跳過
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
//如果實現了PriorityOrdered接口,加入到priorityOrderedPostProcessors
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
//如果實現了Ordered接口,加入到orderedPostProcessorNames
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
//如果既沒有實現PriorityOrdered,也沒有實現Ordered。加入到nonOrderedPostProcessorNames
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
//排序處理priorityOrderedPostProcessors,即實現了PriorityOrdered接口的BeanFactoryPostProcessor
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//執行priorityOrderedPostProcessors
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//執行實現了Ordered接口的BeanFactoryPostProcessor
// 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);
// 執行既沒有實現PriorityOrdered接口,也沒有實現Ordered接口的BeanFactoryPostProcessor
// Finally, invoke all other 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();
}
首先判斷beanFactory是不是BeanDefinitionRegistry的實例,當然肯定是的,然后執行如下操作:
-
定義了一個Set,裝載BeanName,后面會根據這個Set,來判斷后置處理器是否被執行過了。
-
定義了兩個List,一個是regularPostProcessors,用來裝載BeanFactoryPostProcessor,一個是registryProcessors用來裝載BeanDefinitionRegistryPostProcessor,其中BeanDefinitionRegistryPostProcessor擴展了BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor有兩個方法,一個是獨有的postProcessBeanDefinitionRegistry方法,一個是父類的postProcessBeanFactory方法。
-
循環傳進來的beanFactoryPostProcessors,上面已經解釋過了,一般情況下,這里永遠都是空的,只有手動add beanFactoryPostProcessor,這里才會有數據。我們假設beanFactoryPostProcessors有數據,進入循環,判斷postProcessor是不是BeanDefinitionRegistryPostProcessor,因為BeanDefinitionRegistryPostProcessor擴展了BeanFactoryPostProcessor,所以這里先要判斷是不是BeanDefinitionRegistryPostProcessor,是的話,執行postProcessBeanDefinitionRegistry方法,然后把對象裝到registryProcessors里面去,不是的話,就裝到regularPostProcessors。
-
定義了一個臨時變量:currentRegistryProcessors,用來裝載BeanDefinitionRegistryPostProcessor。
-
getBeanNamesForType,顧名思義,是根據類型查到BeanNames,這里有一點需要注意,就是去哪里找,點開這個方法的話,就知道是循環beanDefinitionNames去找,這個方法以后也會經常看到。這里傳了BeanDefinitionRegistryPostProcessor.class,就是找到類型為BeanDefinitionRegistryPostProcessor的后置處理器,並且賦值給postProcessorNames。一般情況下,只會找到一個,就是org.springframework.context.annotation.internalConfigurationAnnotationProcessor,也就是ConfigurationAnnotationProcessor。這個后置處理器在上一節中已經說明過了,十分重要。這里有一個問題,為什么我自己寫了個類,實現了BeanDefinitionRegistryPostProcessor接口,也打上了@Component注解,但是這里沒有獲得,因為直到這一步,Spring還沒有完成掃描,掃描是在ConfigurationClassPostProcessor類中完成的,也就是下面第一個invokeBeanDefinitionRegistryPostProcessors方法。
-
循環postProcessorNames,其實也就是org.springframework.context.annotation.internalConfigurationAnnotationProcessor,判斷此后置處理器是否實現了PriorityOrdered接口(ConfigurationAnnotationProcessor也實現了PriorityOrdered接口),
如果實現了,把它添加到currentRegistryProcessors這個臨時變量中,再放入processedBeans,代表這個后置處理已經被處理過了。當然現在還沒有處理,但是馬上就要處理了。。。 -
進行排序,PriorityOrdered是一個排序接口,如果實現了它,就說明此后置處理器是有順序的,所以需要排序。當然目前這里只有一個后置處理器,就是ConfigurationClassPostProcessor。
-
把currentRegistryProcessors合並到registryProcessors,為什么需要合並?因為一開始spring只會執行BeanDefinitionRegistryPostProcessor獨有的方法,而不會執行BeanDefinitionRegistryPostProcessor父類的方法,即BeanFactoryProcessor接口中的方法,所以需要把這些后置處理器放入一個集合中,后續統一執行BeanFactoryProcessor接口中的方法。當然目前這里只有一個后置處理器,就是ConfigurationClassPostProcessor。
-
可以理解為執行currentRegistryProcessors中的ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry方法,這就是Spring設計思想的體現了,在這里體現的就是其中的熱插拔,插件化開發的思想。Spring中很多東西都是交給插件去處理的,這個后置處理器就相當於一個插件,如果不想用了,直接不添加就是了。這個方法特別重要,我們后面會詳細說來。
-
清空currentRegistryProcessors,因為currentRegistryProcessors是一個臨時變量,已經完成了目前的使命,所以需要清空,當然后面還會用到。
-
再次根據BeanDefinitionRegistryPostProcessor獲得BeanName,然后進行循環,看這個后置處理器是否被執行過了,如果沒有被執行過,也實現了Ordered接口的話,把此后置處理器推送到currentRegistryProcessors和processedBeans中。
這里就可以獲得我們定義的,並且打上@Component注解的后置處理器了,因為Spring已經完成了掃描,但是這里需要注意的是,由於ConfigurationClassPostProcessor在上面已經被執行過了,所以雖然可以通過getBeanNamesForType獲得,但是並不會加入到currentRegistryProcessors和processedBeans。 -
處理排序。
-
合並Processors,合並的理由和上面是一樣的。
-
執行我們自定義的BeanDefinitionRegistryPostProcessor。
-
清空臨時變量。
-
在上面的方法中,僅僅是執行了實現了Ordered接口的BeanDefinitionRegistryPostProcessor,這里是執行沒有實現Ordered接口的BeanDefinitionRegistryPostProcessor。
-
上面的代碼是執行子類獨有的方法,這里需要再把父類的方法也執行一次。
-
執行regularPostProcessors中的后置處理器的方法,需要注意的是,在一般情況下,regularPostProcessors是不會有數據的,只有在外面手動添加BeanFactoryPostProcessor,才會有數據。
-
查找實現了BeanFactoryPostProcessor的后置處理器,並且執行后置處理器中的方法。和上面的邏輯差不多,不再詳細說明。
這就是這個方法中做的主要的事情了,可以說是比較復雜的。但是邏輯還是比較清晰的,在第9步的時候,我說有一個方法會詳細說來,現在就讓我們好好看看這個方法究竟做了什么吧。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();//獲得所有的BeanDefinition的Name,放入candidateNames數組
//循環candidateNames數組
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);//根據beanName獲得BeanDefinition
// 內部有兩個標記位來標記是否已經處理過了
// 這里會引發一連串知識盲點
// 當我們注冊配置類的時候,可以不加Configuration注解,直接使用Component ComponentScan Import ImportResource注解,稱之為Lite配置類
// 如果加了Configuration注解,就稱之為Full配置類
// 如果我們注冊了Lite配置類,我們getBean這個配置類,會發現它就是原本的那個配置類
// 如果我們注冊了Full配置類,我們getBean這個配置類,會發現它已經不是原本那個配置類了,而是已經被cgilb代理的類了
// 寫一個A類,其中有一個構造方法,打印出“你好”
// 再寫一個配置類,里面有兩個bean注解的方法
// 其中一個方法new了A 類,並且返回A的對象,把此方法稱之為getA
// 第二個方法又調用了getA方法
// 如果配置類是Lite配置類,會發現打印了兩次“你好”,也就是說A類被new了兩次
// 如果配置類是Full配置類,會發現只打印了一次“你好”,也就是說A類只被new了一次,因為這個類被cgilb代理了,方法已經被改寫
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//判斷是否為配置類(有兩種情況 一種是傳統意義上的配置類,一種是普通的bean),
//在這個方法內部,會做判斷,這個配置類是Full配置類,還是Lite配置類,並且做上標記
//滿足條件,加入到configCandidates
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果沒有配置類,直接返回
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//處理排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
// DefaultListableBeanFactory最終會實現SingletonBeanRegistry接口,所以可以進入到這個if
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
//spring中可以修改默認的bean命名方式,這里就是看用戶有沒有自定義bean命名方式,雖然一般沒有人會這么做
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析配置類(傳統意義上的配置類或者是普通bean,核心來了)
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);//直到這一步才把Import的類,@Bean @ImportRosource 轉換成BeanDefinition
alreadyParsed.addAll(configClasses);//把configClasses加入到alreadyParsed,代表
candidates.clear();
//獲得注冊器里面BeanDefinition的數量 和 candidateNames進行比較
//如果大於的話,說明有新的BeanDefinition注冊進來了
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();//從注冊器里面獲得BeanDefinitionNames
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));//candidateNames轉換set
Set<String> alreadyParsedClasses = new HashSet<>();
//循環alreadyParsed。把類名加入到alreadyParsedClasses
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
- 獲得所有的BeanName,放入candidateNames數組。
- 循環candidateNames數組,根據beanName獲得BeanDefinition,判斷此BeanDefinition是否已經被處理過了。
- 判斷是否是配置類,如果是的話。加入到configCandidates數組,在判斷的時候,還會標記配置類屬於Full配置類,還是Lite配置類,這里會引發一連串的知識盲點:
3.1 當我們注冊配置類的時候,可以不加@Configuration注解,直接使用@Component @ComponentScan @Import @ImportResource等注解,Spring把這種配置類稱之為Lite配置類, 如果加了@Configuration注解,就稱之為Full配置類。
3.2 如果我們注冊了Lite配置類,我們getBean這個配置類,會發現它就是原本的那個配置類,如果我們注冊了Full配置類,我們getBean這個配置類,會發現它已經不是原本那個配置類了,而是已經被cgilb代理的類了。
3.3 寫一個A類,其中有一個構造方法,打印出“你好”,再寫一個配置類,里面有兩個被@bean注解的方法,其中一個方法new了A類,並且返回A的對象,把此方法稱之為getA,第二個方法又調用了getA方法,如果配置類是Lite配置類,會發現打印了兩次“你好”,也就是說A類被new了兩次,如果配置類是Full配置類,會發現只打印了一次“你好”,也就是說A類只被new了一次,因為這個類被cgilb代理了,方法已經被改寫。
3.4 具體的可以看我的這篇博客:https://www.cnblogs.com/CodeBear/p/10304605.html,里面有詳細的說明。 - 如果沒有配置類直接返回。
- 處理排序。
- 解析配置類,可能是Full配置類,也有可能是Lite配置類,這個小方法是此方法的核心,稍后具體說明。
- 在第6步的時候,只是注冊了部分Bean,像 @Import @Bean等,是沒有被注冊的,這里統一對這些進行注冊。
下面是解析配置類的過程:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
//循環傳進來的配置類
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();//獲得BeanDefinition
try {
//如果獲得BeanDefinition是AnnotatedBeanDefinition的實例
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//執行DeferredImportSelector
processDeferredImportSelectors();
}
因為可以有多個配置類,所以需要循環處理。我們的配置類的BeanDefinition是AnnotatedBeanDefinition的實例,所以會進入第一個if:
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//判斷是否需要跳過
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
} else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
重點在於doProcessConfigurationClass方法,需要特別注意,最后一行代碼,會把configClass放入一個Map,會在上面第7步中用到。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//遞歸處理內部類,一般不會寫內部類
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
// Process any @PropertySource annotations
//處理@PropertySource注解,@PropertySource注解用來加載properties文件
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
} else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
//獲得ComponentScan注解具體的內容,ComponentScan注解除了最常用的basePackage之外,還有includeFilters,excludeFilters等
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
//如果沒有打上ComponentScan,或者被@Condition條件跳過,就不再進入這個if
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
//循環處理componentScans
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//componentScan就是@ComponentScan上的具體內容,sourceClass.getMetadata().getClassName()就是配置類的名稱
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//遞歸調用,因為可能組件類有被@Bean標記的方法,或者組件類本身也有ComponentScan等注解
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
//處理@Import注解
//@Import注解是spring中很重要的一個注解,Springboot大量應用這個注解
//@Import三種類,一種是Import普通類,一種是Import ImportSelector,還有一種是Import ImportBeanDefinitionRegistrar
//getImports(sourceClass)是獲得import的內容,返回的是一個set
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
//處理@ImportResource注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//處理@Bean的方法,可以看到獲得了帶有@Bean的方法后,不是馬上轉換成BeanDefinition,而是先用一個set接收
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
- 遞歸處理內部類,一般不會使用內部類。
- 處理@PropertySource注解,@PropertySource注解用來加載properties文件。
- 獲得ComponentScan注解具體的內容,ComponentScan注解除了最常用的basePackage之外,還有includeFilters,excludeFilters等。
- 判斷有沒有被@ComponentScans標記,或者被@Condition條件帶過,如果滿足條件的話,進入if,進行如下操作:
4.1 執行掃描操作,把掃描出來的放入set,這個方法稍后再詳細說明。
4.2 循環set,判斷是否是配置類,是的話,遞歸調用parse方法,因為被掃描出來的類,還是一個配置類,有@ComponentScans注解,或者其中有被@Bean標記的方法 等等,所以需要再次被解析。 - 處理@Import注解,@Import是Spring中很重要的一個注解,正是由於它的存在,讓Spring非常靈活,不管是Spring內部,還是與Spring整合的第三方技術,都大量的運用了@Import注解,@Import有三種情況,一種是Import普通類,一種是Import ImportSelector,還有一種是Import ImportBeanDefinitionRegistrar,getImports(sourceClass)是獲得import的內容,返回的是一個set,這個方法稍后再詳細說明。
- 處理@ImportResource注解。
- 處理@Bean的方法,可以看到獲得了帶有@Bean的方法后,不是馬上轉換成BeanDefinition,而是先用一個set接收。
我們先來看4.1中的那個方法:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//掃描器,還記不記在new AnnotationConfigApplicationContext的時候
//會調用AnnotationConfigApplicationContext的構造方法
//構造方法里面有一句 this.scanner = new ClassPathBeanDefinitionScanner(this);
//當時說這個對象不重要,這里就是證明了。常規用法中,實際上執行掃描的只會是這里的scanner對象
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//判斷是否重寫了默認的命名規則
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
//addIncludeFilter addExcludeFilter,最終是往List<TypeFilter>里面填充數據
//TypeFilter是一個函數式接口,函數式接口在java8的時候大放異彩,只定義了一個虛方法的接口被稱為函數式接口
//當調用scanner.addIncludeFilter scanner.addExcludeFilter 僅僅把 定義的規則塞進去,並么有真正去執行匹配過程
//處理includeFilters
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
//處理excludeFilters
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
// 從下面的代碼可以看出ComponentScans指定掃描目標,除了最常用的basePackages,還有兩種方式
// 1.指定basePackageClasses,就是指定多個類,只要是與這幾個類同級的,或者在這幾個類下級的都可以被掃描到,這種方式其實是spring比較推薦的
// 因為指定basePackages沒有IDE的檢查,容易出錯,但是指定一個類,就有IDE的檢查了,不容易出錯,經常會用一個空的類來作為basePackageClasses
// 2.直接不指定,默認會把與配置類同級,或者在配置類下級的作為掃描目標
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//把規則填充到排除規則:List<TypeFilter>,這里就把 注冊類自身當作排除規則,真正執行匹配的時候,會把自身給排除
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//basePackages是一個LinkedHashSet<String>,這里就是把basePackages轉為字符串數組的形式
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
- 定義了一個掃描器scanner,還記不記在new AnnotationConfigApplicationContext的時候,會調用AnnotationConfigApplicationContext的構造方法,構造方法里面有一句 this.scanner = new ClassPathBeanDefinitionScanner(this);當時說這個對象不重要,這里就是證明了。常規用法中,實際上執行掃描的只會是這里的scanner對象。
- 處理includeFilters,就是把規則添加到scanner。
- 處理excludeFilters,就是把規則添加到scanner。
- 解析basePackages,獲得需要掃描哪些包。
- 添加一個默認的排除規則:排除自身。
- 執行掃描,稍后詳細說明。
這里需要做一個補充說明,添加規則的時候,只是把具體的規則放入規則類的集合中去,規則類是一個函數式接口,只定義了一個虛方法的接口被稱為函數式接口,函數式接口在java8的時候大放異彩,這里只是把規則方塞進去,並沒有真正執行匹配規則。
我們來看看到底是怎么執行掃描的:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//循環處理basePackages
for (String basePackage : basePackages) {
//根據包名找到符合條件的BeanDefinition集合
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//由findCandidateComponents內部可知,這里的candidate是ScannedGenericBeanDefinition
//而ScannedGenericBeanDefinition是AbstractBeanDefinition和AnnotatedBeanDefinition的之類
//所以下面的兩個if都會進入
if (candidate instanceof AbstractBeanDefinition) {
//內部會設置默認值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//如果是AnnotatedBeanDefinition,還會再設置一次值
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
因為basePackages可能有多個,所以需要循環處理,最終會進行Bean的注冊。下面再來看看findCandidateComponents方法:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//spring支持component索引技術,需要引入一個組件,因為大部分情況不會引入這個組件
//所以不會進入到這個if
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
Spring支持component索引技術,需要引入一個組件,大部分項目沒有引入這個組件,所以會進入scanCandidateComponents方法:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//把 傳進來的類似 命名空間形式的字符串轉換成類似類文件地址的形式,然后在前面加上classpath*:
//即:com.xx=>classpath*:com/xx/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//根據packageSearchPath,獲得符合要求的文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
//循環資源
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {//判斷資源是否可讀,並且不是一個目錄
try {
//metadataReader 元數據讀取器,解析resource,也可以理解為描述資源的數據結構
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//在isCandidateComponent方法內部會真正執行匹配規則
//注冊配置類自身會被排除,不會進入到這個if
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
- 把傳進來的類似命名空間形式的字符串轉換成類似類文件地址的形式,然后在前面加上classpath,即:com.xx=>classpath:com/xx/**/*.class。
- 根據packageSearchPath,獲得符合要求的文件。
- 循環符合要求的文件,進一步進行判斷。
最終會把符合要求的文件,轉換為BeanDefinition,並且返回。
直到這里,上面說的4.1中提到的方法終於分析完畢了,讓我們再看看上面提到的第5步中的處理@Import注解方法:
//這個方法內部相當相當復雜,importCandidates是Import的內容,調用這個方法的時候,已經說過可能有三種情況
//這里再說下,1.Import普通類,2.Import ImportSelector,3.Import ImportBeanDefinitionRegistrar
//循環importCandidates,判斷屬於哪種情況
//如果是普通類,會進到else,調用processConfigurationClass方法
//這個方法是不是很熟悉,沒錯,processImports這個方法就是在processConfigurationClass方法中被調用的
//processImports又主動調用processConfigurationClass方法,是一個遞歸調用,因為Import的普通類,也有可能被加了Import注解,@ComponentScan注解 或者其他注解,所以普通類需要再次被解析
//如果Import ImportSelector就跑到了第一個if中去,首先執行Aware接口方法,所以我們在實現ImportSelector的同時,還可以實現Aware接口
//然后判斷是不是DeferredImportSelector,DeferredImportSelector擴展了ImportSelector
//如果不是的話,調用selectImports方法,獲得全限定類名數組,在轉換成類的數組,然后再調用processImports,又特么的是一個遞歸調用...
//可能又有三種情況,一種情況是selectImports的類是一個普通類,第二種情況是selectImports的類是一個ImportBeanDefinitionRegistrar類,第三種情況是還是一個ImportSelector類...
//所以又需要遞歸調用
//如果Import ImportBeanDefinitionRegistrar就跑到了第二個if,還是會執行Aware接口方法,這里終於沒有遞歸了,會把數據放到ConfigurationClass中的Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars中去
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
} else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
} else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
} else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
} finally {
this.importStack.pop();
}
}
}
這個方法大概的作用已經在注釋中已經寫明了,就不再重復了。
直到這里,才把ConfigurationClassPostProcessor中的processConfigBeanDefinitions方法簡單的過了一下。
但是這還沒有結束,processConfigBeanDefinitions是BeanDefinitionRegistryPostProcessor接口中的方法,BeanDefinitionRegistryPostProcessor擴展了BeanFactoryPostProcessor,還有postProcessBeanFactory方法沒有分析,這個方法是干嘛的,簡單的來說,就是判斷配置類是Lite配置類,還是Full配置類,如果是配置類,就會被Cglib代理,目的就是保證Bean的作用域。關於這個方法實在是比較復雜,限於篇幅原因,這里就不再繼續了,有興趣的朋友可以到我的GitHub看下,里面有簡單的分析(當然其實還有很多東西無法在博客中體現,如果都貼出來的話,實在是太長了,但是在GitHub上面都有注釋)。
我們來做一個總結,ConfigurationClassPostProcessor中的processConfigBeanDefinitions方法十分重要,主要是完成掃描,最終注冊我們定義的Bean。