前言spring
前段時間旁聽了某課堂兩節Spring源碼解析課,恰好最近本身又在從新學習中,便在這裏記錄一下學習所得。我以前寫過一篇博文,是介紹BeanFactoryPostProcessor跟BeanPostProcessor是如何發揮做用的,當時以爲講的還行,可是如今看來,太粗劣了,不少地方沒涉及到,並且重點都被我忽略了,簡直就是蠢得不行。如今就用這篇文章彌補一下前文中對BeanFactoryPostProcessor的講解,爭取把重點講到,至於BeanPostProcessor,因爲涉及到的東西太多,限於本人目前的水平只能做罷,待後面感悟成熟了再來補充。app
咱們以AnnotationConfigApplicationContext爲例來構建測試類,先附上這次打斷點調試的三個簡約到極致的測試類:post
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 }
一、洞悉啓動容器時的準備工做學習
熟悉一些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()方法。點進去後發現是這樣的:ui
1 public AnnotationConfigApplicationContext() { 2 this.reader = new AnnotatedBeanDefinitionReader(this); 3 this.scanner = new ClassPathBeanDefinitionScanner(this); 4 }
在第二行新建reader對象時,調用了這個構造方法:this
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方法中一探究竟。lua
二、invokeBeanFactoryPostProcessorsspa
該方法位於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及其子接口的實現類,逐一對重寫方法進行調用。
雖然魔鬼在細節,但這也正是解讀源碼的快樂之處,不是嗎?