spring 5.0.x源码学习系列三: AnnotationConfigApplicationContext类的无参构造方法的作用

前言

后续的所有文章将开始围绕上篇博客:spring 5.0.x源码学习系列二: 从AnnotationConfigApplicationContext开始,进入spring世界的运行流程图展开, 并根据实际的代码来详细解析。接下来开始进入正文

一、AnnotationConfigApplicationContext的无参构造方法

上篇博客(上面有链接, 可以自行查看)中,大致介绍了无参构造方法的主要作用, 接下来将根据源码详细介绍.

1.1 项目demo

项目结构非常简单,大致结构如下:


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.2 debug运行项目

1. 进入带参AnnotationConfigApplicationContext构造方法

在这里插入图片描述

2. 调用无参构造方法, 但因为继承了GenericApplicationContext类, 所以要先执行父类的无参构造方法, 此时实例化了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需要注册, 注册方式跟第八步大同小异,都是先判断是否存在再创建RootBeanDefinition再注册到bean工厂, 这里就不累述了

  • 具体还剩哪5个内置bean可以参考我的上一篇博客spring 5.0.x源码学习系列二: 从AnnotationConfigApplicationContext开始,进入spring世界的第一封流程图, 或者看下面的源码
        public static Set 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 beanDefs = new LinkedHashSet<>(8);
    
            // 验证bean工厂中是否包含名字叫 "这么一长串的beanDefinition" - -!
            // 什么叫BeanDefinition呢? Java中描述一个类(比如常用的User类)是用
            // 类型为Class的类来描述, 在spring中是用BeanDefinition来描述一个bean
            // 的。使用过spring的人就明白, 一个beans可以设置有许多属性, 比如scope、lazy、description、bean的class、bean的name等等.
            // BeanDefinition就是用来存储这些信息的, 在spring创建bean时, 会拿到这个bean对应的beanDefinition信息来创建它。
            // BeanDefinition的类型有许多种, 比如: 现在看到的RootBeanDefinition、AnnotatedBeanDefinition、ScannedGenericBeanDefinition等等,
            // 每个bean都有不同的作用, 比如ScannedGenericBeanDefinition类型的beanDefinition,
            // 咱们可以为这样的beanDefinition手动设置它的自动装配模式(Mybatis集成spring的源码中利用了这一点,后续有机会再记录总结)。
            // 在往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对象, 所以暂时没发现它有啥用, 先跳过它, 以后若发现它有其他作用再来补上

二、小结

  • AnnotationConfigApplicationContext类的无参构造方法的主要作用就是:初始化bean工厂注册spring的6个内置bean
  • 需要着重记住的几个东西:
  1. spring的bean工厂类: DefaultListableBeanFactory
  2. spring中最重要的内置bean: ConfigurationClassPostProcessor, 它的作用在refresh方法中会着重体现出来, 后续再总结
  3. BeanDefinition的定义: 描述spring bean的数据结构
  4. BeanDefinition的几种类型: RootBeanDefinitionAnnotatedGenericBeanDefinitionScannedGenericBeanDefinitionConfigurationClassBeanDefinition(配置类中方法中拥有@Bean注解的类会被定义成这个)
  5. spring上下文的几种身份: BeanDefinitionRegistryGenericApplicationContex
  • spring源码学习对应GitHub 地址https://github.com/AvengerEug/spring/tree/develop/resourcecode-study
  • I am a slow walker, but I never walk backwards.

你可能感兴趣的:(spring 5.0.x源码学习系列三: AnnotationConfigApplicationContext类的无参构造方法的作用)