前言
前段時間旁聽了某課堂兩節Spring原始碼解析課,剛好最近自己又在重新學習中,便在這裡記錄一下學習所得。我之前寫過一篇博文,是介紹BeanFactoryPostProcessor跟BeanPostProcessor是如何發揮作用的,當時覺得講的還行,但是現在看來,太粗劣了,很多地方沒涉及到,而且重點都被我忽略了,簡直就是蠢得不行。現在就用這篇文章彌補一下前文中對BeanFactoryPostProcessor的講解,爭取把重點講到,至於BeanPostProcessor,由於涉及到的東西太多,限於本人目前的水平只能作罷,待後面感悟成熟了再來補充。
我們以AnnotationConfigApplicationContext為例來構建測試類,先附上此次打斷點除錯的三個簡約到極致的測試類:
1 public class SpringTest { 2 3 public static void main(String[] args) { 4 // 從這兩行程式碼,實地跟蹤考察Spring中的流程 5 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanConfig.class); 6 applicationContext.getBean(Teacher.class).teach(); 7 } 8 }
1 package myPackage; 2 import org.springframework.stereotype.Service; 3 4 @Service 5 public class Teacher { 6 public Teacher () { 7 System.out.println("Teacher init"); 8 } 9 public void teach () { 10 System.out.println("teach"); 11 } 12 }
1 package myPackage; 2 import org.springframework.context.annotation.ComponentScan; 3 4 @ComponentScan("myPackage") 5 public class ScanConfig { 6 }
1、洞悉啟動容器時的準備工作
熟悉一些Spring的道友應該都知道,refresh方法中的invokeBeanFactoryPostProcessors方法實現了對BeanFactoryPostProcessor實現類的處理。大家如果只看invokeBeanFactoryPostProcessors方法的話,不會發現有何異常之處,此方法雖然較長,但是處理邏輯很清晰,先對重寫了BeanFactoryPostProcessor的子介面BeanDefinitionRegistryPostProcessor方法的實現類進行處理,後對重寫了BeanFactoryPostProcessor的方法的實現類做了處理。但是如果心細的話,你會發現問題,Spring是如何將@ComponentScan("myPackage")註解發揮作用的?這時帶著這樣的問題,我們再回過頭來看容器的構造方法,就會在這平實的表面下發現意想不到的 "殺機"。
1 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { 2 this(); 3 register(annotatedClasses); 4 refresh(); 5 }
通過這個構造方法可以知道,在第二行將我們的測試類ScanConfig 註冊進了容器中,但這只是註冊,註冊之後是如何呼叫如何實現了@ComponentScan("myPackage")這個註解的包掃描的呢?這時我們將目光鎖定this()方法。點進去後發現是這樣的:
1 public AnnotationConfigApplicationContext() { 2 this.reader = new AnnotatedBeanDefinitionReader(this); 3 this.scanner = new ClassPathBeanDefinitionScanner(this); 4 }
在第二行新建reader物件時,呼叫了這個構造方法:
1 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { 2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 3 Assert.notNull(environment, "Environment must not be null"); 4 this.registry = registry; 5 this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); 6 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 7 }
其中的第六行,最終呼叫了AnnotationConfigUtils#registerAnnotationConfigProcessors方法,而就是在這個方法中完成了對多個重要Bean的註冊,跟我們關係比較大的有以下幾個:
1 // BeanDefinitionHolder只是存放BD的,裡面有三個屬性:BD物件、beanName以及別名組成的String[] 2 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4); 3 // 註冊最關鍵的類,對應的類為ConfigurationClassPostProcessor,父類的父類是BeanFactoryPostProcessor 4 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { 5 RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); 6 def.setSource(source); 7 // 將BD注入進容器中,沒經過什麼處理,只是放入了DefaultListableBeanFactory中的beanDefinitionMap跟存放beanName的list中 8 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); 9 } 10 // 此類實現了BeanPostProcessor,用於處理@Autowired、@Value註解 11 if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { 12 RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); 13 def.setSource(source); 14 beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); 15 } 16 // 此類也實現了BeanPostProcessor,用於處理有@Required註解的方法 17 if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { 18 RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class); 19 def.setSource(source); 20 beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); 21 }
其中第一個對應的類就是我們重點關注的物件 ConfigurationClassPostProcessor類,檢視此類的組成,發現它實現了BeanDefinitionRegistryPostProcessor介面,而此介面正是BeanFactoryPostProcessor的子介面。此時,縈繞在我們心頭的迷霧開始漸漸散開,我們彷彿能抓到一閃而過的邏輯走向,現在讓我們帶著之前的發現,進入正主invokeBeanFactoryPostProcessors方法中一探究竟。
2、invokeBeanFactoryPostProcessors
該方法位於AbstractApplicationContext的refresh方法中,如下所示:
1 public void refresh() throws BeansException, IllegalStateException {
2 synchronized (this.startupShutdownMonitor) {
3 // Prepare this context for refreshing.
4 prepareRefresh();
5
6 // Tell the subclass to refresh the internal bean factory.
7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
8
9 // Prepare the bean factory for use in this context.
10 prepareBeanFactory(beanFactory);
11
12 try {
13 // Allows post-processing of the bean factory in context subclasses.
14 postProcessBeanFactory(beanFactory);
15
16 // Invoke factory processors registered as beans in the context.
17 invokeBeanFactoryPostProcessors(beanFactory);
即第17行呼叫的方法。初學者看到這個方法的內部實現時,會發現此方法無外乎是找到所有實現了BeanDefinitionRegistryPostProcessor跟BeanFactoryPostProcessor介面的類,按照優先順序(實現了PriorityOrdered介面的先於實現了Ordered介面,前兩者均先於未實現的,且同一類中按照getOrder方法返回值排優先順序)順序執行它們的重寫方法,先執行BeanDefinitionRegistryPostProcessor的重寫方法,再執行BeanFactoryPostProcessor的重寫方法,很容易理解的邏輯。但是現在我們是帶著前面準備工作中得到的線索來的,此時再看,就能透過這個方法樸實的外表發現它潛藏的凶險,它如平地一聲雷般讓人猛地驚出一身冷汗。
我們打斷點進入PostProcessorRegistrationDelegate類中的下面方法中
1 public static void invokeBeanFactoryPostProcessors( 2 ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {}
先略過開始對手動新增進去的beanFactoryPostProcessors處理邏輯,看後面的部分程式碼(由於此方法程式碼較多,此處就不全部貼上出來了,因為邏輯很好理解,所以只貼上重點):
1 String[] postProcessorNames = 2 beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); 3 4 // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. 5 List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>(); 6 // 1.2 先處理實現了PriorityOrdered的類 7 for (String ppName : postProcessorNames) { 8 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { 9 // 此處通過getBean來生成ConfigurationClassPostProcessor例項物件 10 priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); 11 processedBeans.add(ppName); 12 } 13 } 14 // 就一個物件,有啥好排序的 15 sortPostProcessors(beanFactory, priorityOrderedPostProcessors); 16 registryPostProcessors.addAll(priorityOrderedPostProcessors); 17 // 執行ConfigurationClassPostProcessor中的重寫方法postProcessBeanDefinitionRegistry,會將所有加了註解的類註冊到容器中 18 // 此處才是整個invokeBeanFactoryPostProcessors方法的核心所在,需要詳述 下面進入ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry中一探究竟 19 invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
debug到第一行的時候,會發現此處獲取到的postProcessorNames 中只有一個值,就是前面準備工作中通過硬編碼往容器裡註冊的ConfigurationClassPostProcessor類。下面的邏輯就是進行各種判斷,最後在第19行完成了對ConfigurationClassPostProcessor中postProcessBeanDefinitionRegistry方法的呼叫。
就是在這個後置處理方法中,完成了@ComponentScan("myPackage")中對包的掃描,完成了所有Bean的註冊。執行完這個方法後,你會發現beanDefinitionMap中所有應該容器管理的類全都齊活了,包括其他的後置處理器。這樣,後面繼續呼叫beanFactory.getBeanNamesForType方法時,獲取到的是所有滿足條件的類,後面的工作就會有條不紊的開展下去了。
總結
本文著重追溯了BeanFactoryPostProcessor及其子介面是如何在Spring中發揮作用的。先通過Spring初始化容器時註冊進去的ConfigurationClassPostProcessor類觸發對其他類的掃描,待全部註冊進容器後,再從容器中取對應的BeanFactoryPostProcessor及其子介面的實現類,逐一對重寫方法進行呼叫。
雖然魔鬼在細節,但這也正是解讀原始碼的快樂之處,不是嗎?