spring 5.0.x源碼學習系列三: AnnotationConfigApplicationContext類的無參構造方法的作用

前言

后續(xù)的所有文章將開始圍繞上篇博客:spring 5.0.x源碼學習系列二: 從AnnotationConfigApplicationContext開始,進入spring世界的運行流程圖展開, 并根據實際的代碼來詳細解析。接下來開始進入正文

一、AnnotationConfigApplicationContext的無參構造方法

上篇博客(上面有鏈接, 可以自行查看)中,大致介紹了無參構造方法的主要作用, 接下來將根據源碼詳細介紹.

1.1 項目demo

項目結構非常簡單,大致結構如下:


在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述

1.2 debug運行項目

1. 進入帶參AnnotationConfigApplicationContext構造方法

在這里插入圖片描述

2. 調用無參構造方法, 但因為繼承了GenericApplicationContext類, 所以要先執(zhí)行父類的無參構造方法, 此時實例化了bean工廠

在這里插入圖片描述

3. bean工廠初始化完畢

在這里插入圖片描述

4. 實例化AnnotationBeanDefinitionReader

在這里插入圖片描述

5. AnnotationBeanDefinitionReader自己維護了spring的上下文, 并開始準備注冊spring的6個內置bean

在這里插入圖片描述

6. 重載方法

在這里插入圖片描述

7. 從BeanDefinitionRegistry中獲取bean工廠

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

8. 注冊spring的六個內置bean(這些bean的作用是后置處理器)

  • 源碼注釋圖

    在這里插入圖片描述
  • 判斷是否存在beanName

        //AbstractApplicationContext.java
        @Override
        public boolean containsBeanDefinition(String beanName) {
            // getBeanFactory()獲取的是DefaultListableBeanFactory, 
            // 所有會進到DefaultListableBeanFactory的containsBeanDefinition
            // 方法中
            return getBeanFactory().containsBeanDefinition(beanName);
        }
    
        // DefaultListableBeanFactory.java
        @Override
        public boolean containsBeanDefinition(String beanName) {
            Assert.notNull(beanName, "Bean name must not be null");
            return this.beanDefinitionMap.containsKey(beanName);
        }
    
  • 注冊spring內置bean源碼

        // 注冊spring內置bean的源碼
        private static BeanDefinitionHolder registerPostProcessor(
                BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
    
            definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            // 這行代碼很重要, 在spring中基本上所有的beanDefinition的注冊
            // 都要走BeanDefinitionRegistry的registerBeanDefinition方法。
            // spring的單一原則做的真好(真香!)
            // 這里的register又是哪個對象呢? 同樣的它是AnnotationConfigApplicationContext
            // 但registerBeanDefinition方法的調用不在父類的父類, 
            // 而是在父類GenericApplicationContext中
            registry.registerBeanDefinition(beanName, definition);
            return new BeanDefinitionHolder(definition, beanName);
        }
    

9. 后面還有5個內置bean需要注冊, 注冊方式跟第八步大同小異,都是先判斷是否存在再創(chuàng)建RootBeanDefinition再注冊到bean工廠, 這里就不累述了

  • 具體還剩哪5個內置bean可以參考我的上一篇博客spring 5.0.x源碼學習系列二: 從AnnotationConfigApplicationContext開始,進入spring世界的第一封流程圖, 或者看下面的源碼
        public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
                BeanDefinitionRegistry registry, @Nullable Object source) {
            // 此處是為了獲取bean工廠, 獲取bean工廠的目的很簡單, 就是為了注冊spring內置的六個bean
            DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
            if (beanFactory != null) {
                // 不知道具體干啥的, 后面有機會再補充
                if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                    beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
                }
                
                // 添加一個上下文注解自動裝配的候選解析器(具體做啥的, 目前還沒研究到)
                if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
                }
            }
            // 存儲BeanDefinitionHolder的set集合, 在注冊spring內置bean這一過程中, 這個變量沒用, 雖然方法中return了, 但調用的地方并沒有接收它
            Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    
            // 驗證bean工廠中是否包含名字叫 "這么一長串的beanDefinition" - -!
            // 什么叫BeanDefinition呢? Java中描述一個類(比如常用的User類)是用
            // 類型為Class的類來描述, 在spring中是用BeanDefinition來描述一個bean
            // 的。使用過spring的人就明白, 一個beans可以設置有許多屬性, 比如scope、lazy、description、bean的class、bean的name等等.
            // BeanDefinition就是用來存儲這些信息的, 在spring創(chuàng)建bean時, 會拿到這個bean對應的beanDefinition信息來創(chuàng)建它。
            // BeanDefinition的類型有許多種, 比如: 現在看到的RootBeanDefinition、AnnotatedBeanDefinition、ScannedGenericBeanDefinition等等,
            // 每個bean都有不同的作用, 比如ScannedGenericBeanDefinition類型的beanDefinition,
            // 咱們可以為這樣的beanDefinition手動設置它的自動裝配模式(Mybatis集成spring的源碼中利用了這一點,后續(xù)有機會再記錄總結)。
            // 在往bean工廠注冊beanDefinition時, 會往兩個數據結構中存值, 一個是叫
            // beanDefinitionMap另一個叫beanDefinitionNames。顧名思義, 分別是用來存儲beanDefinition(key為bean name)和bean name
            if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                // spring內置bean的beanDefinition類型為RootBeanDefinition
                RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
                // 傳入的為null, 所以先不管它
                def.setSource(source);
                // 這行代碼做了兩件事, 一件是注冊bean, 另一件是添加到beanDefs, 雖然它的方法名叫注冊后置處理器, 但方法內部還是注冊beanDefinition
                // 這里又用到了registry, 這個registry就是spring上下文
                beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
    
            if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
    
            if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
    
            // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
            if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
    
            // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
            if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition();
                try {
                    def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                            AnnotationConfigUtils.class.getClassLoader()));
                }
                catch (ClassNotFoundException ex) {
                    throw new IllegalStateException(
                            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
                }
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
    
            if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
            }
    
            if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
            }
    
            return beanDefs;
        }
    

10. spring內置6個bean注冊完畢

在這里插入圖片描述

11. this.scanner = new ClassPathBeanDefinitionScanner(this)

關于這行代碼, 它是初始化一個ClassPath的掃描器, 它的作用是掃描@ComponentScan注解中提供的掃描路徑, 但它并沒有起到這個作用, 因為真正在解析@ComponentScan注解時, 是在內部新new了一個ClassPathBeanDefinitionScanner對象, 所以暫時沒發(fā)現它有啥用, 先跳過它, 以后若發(fā)現它有其他作用再來補上

二、小結

  • AnnotationConfigApplicationContext類的無參構造方法的主要作用就是:初始化bean工廠、注冊spring的6個內置bean
  • 需要著重記住的幾個東西:
  1. spring的bean工廠類: DefaultListableBeanFactory
  2. spring中最重要的內置bean: ConfigurationClassPostProcessor, 它的作用在refresh方法中會著重體現出來, 后續(xù)再總結
  3. BeanDefinition的定義: 描述spring bean的數據結構
  4. BeanDefinition的幾種類型: RootBeanDefinition、AnnotatedGenericBeanDefinition、ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition(配置類中方法中擁有@Bean注解的類會被定義成這個)
  5. spring上下文的幾種身份: BeanDefinitionRegistryGenericApplicationContex
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容