Spring5源码解析2-register方法注册配置类

接上回已经讲完了this()方法,现在来看register(annotatedClasses);方法。

// new AnnotationConfigApplicationContext(AppConfig.class); 源码
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    //调用默认无参构造器,里面有一大堆初始化逻辑
    this();

    //把传入的Class进行注册,Class既可以有@Configuration注解,也可以没有@Configuration注解
    //怎么注册? 委托给了 org.springframework.context.annotation.AnnotatedBeanDefinitionReader.register 方法进行注册
    // 传入Class 生成  BeanDefinition , 然后通过 注册到 BeanDefinitionRegistry
    register(annotatedClasses);

    //刷新容器上下文
    refresh();
}

register(annotatedClasses) 方法

register(annotatedClasses);方法最后其实是调用了readerdoRegisterBean(annotatedClass, null, null, null);方法。

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
                        @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    //根据传入的Class对象生成  AnnotatedGenericBeanDefinition ,
    // AnnotatedGenericBeanDefinition 是 BeanDefinition 的 一个实现类
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //根据 @Conditional 注解,判断是否需要跳过解析
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
        return;
    }

    abd.setInstanceSupplier(instanceSupplier);
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

    //解析 Class<T> annotatedClass 是否有通用注解: @Lazy,@Primary,@DependsOn,@Role,@Description
    // 并把解决结果放入 AnnotatedBeanDefinition 中
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

    //Class<? extends Annotation>[] qualifiers 是通过方法调用传入的
    // 上一步是解析Class中是否有注解,这一步是调用方作为参数传入的
    if (qualifiers != null) {
        for (Class<? extends Annotation> qualifier : qualifiers) {
            if (Primary.class == qualifier) {
                abd.setPrimary(true);
            } else if (Lazy.class == qualifier) {
                abd.setLazyInit(true);
            } else {
                //org.springframework.beans.factory.support.AbstractBeanDefinition.qualifiers
                //Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
                //直接放入map中
                abd.addQualifier(new AutowireCandidateQualifier(qualifier));
            }
        }
    }
    for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
        customizer.customize(abd);
    }

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

    //将该Class<T> annotatedClass 转为 BeanDefinition 后, 通过再封装为 BeanDefinitionHolder 对象,进行 registerBeanDefinition
    //AnnotatedBeanDefinitionReader 中有一个 BeanDefinitionRegistry registry 是通过构造方法传入的
    //new AnnotationConfigApplicationContext(AppConfig.class); AnnotationConfigApplicationContext extends GenericApplicationContext
    // GenericApplicationContext 类 实现了 BeanDefinitionRegistry ,registry 即为 AnnotationConfigApplicationContext
    // GenericApplicationContext 类 内部 是 通过 DefaultListableBeanFactory 来实现 BeanDefinitionRegistry 接口的
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
  1. 根据传入的class对象创建AnnotatedGenericBeanDefinitionAnnotatedGenericBeanDefinitionBeanDefinition 的一个实现类。
  2. 根据@Conditional 注解,判断是否需要跳过解析,很明显这里不需要,返回false,代码继续向下执行。
  3. 根据传入的参数,设置BeanDefinition 的属性
  4. 解析传入的class对象是否有通用注解(@Lazy@Primary@DependsOn@Role@Description),并把解析结果放入 AnnotatedBeanDefinition中。
  5. 判断是否有传入Class<? extends Annotation>[] qualifiers参数,如果不为null,则将传入的qualifiers参数设置到BeanDefinition中。注意,第4步解析的是class中是否带有通用注解。而这步判断的注解是调用方手动传入的。
  6. 将传入的class对象转化为 BeanDefinition后,再将BeanDefinition封装到BeanDefinitionHolder中(为了方便传参),然后调用BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);注册该 BeanDefinition
  7. 调用registerBeanDefinition方法时传入的this.registry对象是AnnotatedBeanDefinitionReader的一个属性,它是在构造方法中被初始化的。这个this.registry对象其实就是AnnotationConfigApplicationContext对象。AnnotationConfigApplicationContext 继承了GenericApplicationContextGenericApplicationContext类实现了BeanDefinitionRegistry接口。而在GenericApplicationContext类中其实是委托给成员变量beanFactory来实现BeanDefinitionRegistry接口的。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

    private final DefaultListableBeanFactory beanFactory;
  1. 再来看registerBeanDefinition方法。主要是通过registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法将BeanDefinition注册到DefaultListableBeanFactory中,也就是spring容器中。
public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

而所谓的注册BeanDefinition,简单理解就是将BeanDefinition放到DefaultListableBeanFactory对象的beanDefinitionMap中。

//org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法源码
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    //第一次进来existingDefinition肯定为null
    if (existingDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        } else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                        "' with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                        "' with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        } else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                        "' with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        } else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

运行完register(annotatedClasses);方法之后,spring容器中还没有实例化bean,而只是注册了一些BeanDefinition。(注册的是Spring内部一些postProcessor和我们代码传入的AppConfig类)。



源码学习笔记GITHUB仓库地址:https://github.com/shenjianeng/spring-code-study

欢迎各位关注公众号:

原文地址:https://www.cnblogs.com/coderxiaohei/p/11631413.html

时间: 2024-07-29 23:14:04

Spring5源码解析2-register方法注册配置类的相关文章

[EventBus源码解析] EventBus.register 方法详述

前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制. 本篇概述 剖析register的过程,let's get started! 方法签名 完整的register方法签名如下,我们通常调用的register(this)其实最终调用到的register(this, false, 0),另外,使用registerSticky(this)进行调用,其实最

十七.jQuery源码解析之入口方法Sizzle(1)

函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: 1.解析选择器表达式,解析出块表达式和关系符. 2.如果存在位置伪类,则从左向右查找: a.查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合. b.遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合. 3.否则从右向左查找: a.查找最后一个块表达式匹配的元素集合,得到候选集,映射集

Spring-cloud &amp; Netflix 源码解析:Eureka 服务注册发现接口 ****

http://www.idouba.net/spring-cloud-source-eureka-client-api/?utm_source=tuicool&utm_medium=referral *************************** 先关注下netflix eureka server 原生提供的接口.https://github.com/Netflix/eureka/wiki/Eureka-REST-operations 这是对非java的服务使用eureka时可以使用的r

多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面大致的了解了Thread的一些方法和属性下面对一些方法进行运用看看具体效果<下面可能还是会贴很多的源代码,其实我是拒绝的,我只想贴每个方法的代码,但是有时候看到一个方法里面有调用了方法,但是笔者有没有给出来,很蛋疼,有种爽到一半的感觉,所以我还是会把它贴出来,希望一次就能挖到底,不论有没有全懂,但至

springIOC源码解析之BeanDefinition的注册

ApplicationContext类结构 context是一个存储上下文结构的东西,里面会引用BeanFactory  BeanFactory类结构 我们从这句代码开始分析,(本文spring采用的是4.2.4的版本) ApplicationContext con = new FileSystemXmlApplicationContext("src/test/java/com//spring/test/beans-factorybean.xml"); public FileSyste

Spring5源码解析1-从启动容器开始

从启动容器开始 最简单的启动spring的代码如下: @Configuration @ComponentScan public class AppConfig { } public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); con

Spring5源码解析-Spring框架中的事件和监听器

事件和平时所用的回调思想在与GUI(JavaScript,Swing)相关的技术中非常流行.而在Web应用程序的服务器端,我们很少去直接使用.但这并不意味着我们无法在服务端去实现一个面向事件的体系结构. 在本文中,我们将重点介绍Spring框架中的事件处理.首先,会先介绍下事件驱动编程这个概念.接着,我们会将精力放在专门用于Spring框架中的事件处理之上.然后我们会看到实现事件调度和监听的主要方法.最后,我们将在Spring应用程序中展示如何使用基本的监听器. 事件驱动编程 在开始讨论事件驱动

Spring5源码解析-前奏:本地构建Spring5源码

构建环境 macOS 10.13.6 JDK1.8 IntelliJ IDEA 2018.3.6 (Ultimate Edition) Spring v5.1.9.RELEASE Gradle 5.5.1.直接使用brew安装Gradle brew install gradle 源码构建 源码导入 阅读Spring源码下的 import-into-idea.md 文件可知 Precompile spring-xingtuylgw.com oxm with ./gradlew :spring-ox

HashMap源码解析之resize方法

resize函数 因为HashMap的构造函数 并不会给内部的表开辟空间 而是在调用put函数时 如果表为空 调用resize方法 换句话说 resize函数不得不 考虑 任何不同形式的构造函数 及带一参 带两参 不带参的构造函数 调用resize方法 并且 当表中的数量 超过临界值时 也会调用resize方法 所以整个 大概思路 旧表保存下来 定义并赋值 旧表的长度 临界值 如果旧表为空则长度为0 定义新表长度 新表临界值 如果旧表中有元素 4.1 判断是否达最大长度 到达则无需再散列 4.2