Spring源碼解讀之BeanFactoryPostProcessor的處理

前言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及其子接口的實現類,逐一對重寫方法進行調用。

雖然魔鬼在細節,但這也正是解讀源碼的快樂之處,不是嗎?