接上回已经讲完了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);方法最后其实是调用了reader的doRegisterBean(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对象创建AnnotatedGenericBeanDefinition,AnnotatedGenericBeanDefinition 是 BeanDefinition 的一个实现类。
  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 继承了GenericApplicationContext,GenericApplicationContext类实现了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

欢迎各位关注公众号:

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

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

    前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制 ...

  2. Spring5源码解析系列一——IoC容器核心类图

    基本概念梳理 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现.我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象 ...

  3. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

  4. Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean

    Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...

  5. Spring5源码解析-论Spring DispatcherServlet的生命周期

    Spring Web框架架构的主要部分是DispatcherServlet.也就是本文中重点介绍的对象. 在本文的第一部分中,我们将看到基于Spring的DispatcherServlet的主要概念: ...

  6. Spring5源码解析_IOC之容器的基本实现

    前言: 在分析源码之前,我们简单回顾一下SPring核心功能的简单使用: 容器的基本用法 Bean是Spring最核心的东西,Spring就像是一个大水桶,而Bean就是水桶中的水,水桶脱离了水就没有 ...

  7. 一文带你解读Spring5源码解析 IOC之开启Bean的加载,以及FactoryBean和BeanFactory的区别。

    前言 通过往期的文章我们已经了解了Spring对XML配置文件的解析,将分析的信息组装成BeanDefinition,并将其保存到相应的BeanDefinitionRegistry中,至此Spring ...

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

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

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

    http://www.idouba.net/spring-cloud-source-eureka-client-api/?utm_source=tuicool&utm_medium=refer ...

  10. [Java多线程]-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

随机推荐

  1. post请求四种传送正文的方式

    一.简介 HTTP协议规定post提交的数据必须放在消息主体(entity-body)中,但协议没有规定数据必须使用什么编码方式.HTTP协议是以ASCII码传输,建立再TCP/IP协议之上的应用层规 ...

  2. HTML中跨域请求天气粗略效果

    HTML中跨域请求天气粗略效果 html+css部分: <style> table{ border:1px red solid; border-collapse: collapse; ma ...

  3. node 升级版本

    1.安装 更新node.js版本 命令 [root@node ~]# npm install -g n /home/meisapp/node/node-v6.10.0-linux-x64/bin/n ...

  4. ES&IK环境搭建

    本来打算docker安装es,和腾讯云上的服务器相比,一台赤裸裸的本地机,甚至连很多基础的指令都没有,还花样各种报错,对于我这种新手来说简直了,百度啊cddn啊终于整出来了,记录一下: 一:安装依赖 ...

  5. Java题库——Chapter2 基础程序设计

    1)Suppose a Scanner object is created as follows: Scanner input = new Scanner(System.in); What metho ...

  6. 双系统卸载ubuntu

    转载自https://www.jianshu.com/p/30795695be95 如果开机是这样子的,就是ubuntu引导windows(专业名词gpt) ubuntu引导windows 那么先进w ...

  7. Initialize a Property After Creating an Object 创建对象后初始化属性 (XPO)

    In this lesson, you will learn how to set the default value for a particular property of a business ...

  8. JQuery iframe宽高度自适应浏览器窗口大小的解决方法

    iframe宽高度自适应浏览器窗口大小的解决方法   by:授客 QQ:1033553122 1.   测试环境 JQuery-3.2.1.min.js 下载地址: https://gitee.com ...

  9. 一文解读MVC/MVP/MVVM (转)

    这篇文章对目前 GUI 应用中的 MVC.MVP 和 MVVM 架构模式进行详细地介绍. MVC 在整个 GUI 编程领域,MVC 已经拥有将近 50 年的历史了.早在几十年前,Smalltalk-7 ...

  10. 面向对象OPP

      在此之前学习的编程方式均称为面向过程,过程类似于函数,只能执行,没有返回值 面向过程和面向对象 面向过程-->怎么做? 面向对象-->谁来做? 相比函数,面向对象 是更大的封装,根据职 ...