Spring之BeanDefinition(三)

news2024/9/22 11:27:59

Spring之BeanDefinition(三)

文章目录

  • Spring之BeanDefinition(三)
    • 一、Spring的启动类三行代码研究
    • 二、Spring创建工厂类型和属性
    • 三、Spring中内置的BeanDefinition
    • 四、注册配置类
    • 五、BeanDefinition总结

一、Spring的启动类三行代码研究

一切还是得从spring中的三行代码说起:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(LiAppCOnfig.class);
applicationContext.refresh();

下面的研究就需要从这三行代码分别来进行说明。

二、Spring创建工厂类型和属性

首先从第一行代码开始研究

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

从第一行代码进去,看一下源码说明:

	public AnnotationConfigApplicationContext() {
        // 创建Spring中的容器对象: this.beanFactory = new DefaultListableBeanFactory();
        // 这行代码是我自己添加的!因为默认访问的就是父类中的默认无参构造方法
		super();
		// ....
	}

而在new DefaultListableBeanFactory()的时候,首先可以知道的是beanFactory是DefaultListableBeanFactory类型

可以看一下其中的现有的成员属性变量:

/** Whether to allow re-registration of a different definition with the same name. */
private boolean allowBeanDefinitionOverriding = true;

/** Whether to allow eager class loading even for lazy-init beans. */
private boolean allowEagerClassLoading = true;


/** Resolver to use for checking if a bean definition is an autowire candidate. */
private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;

/** Map from dependency type to corresponding autowired value. */
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

/** Map from bean name to merged BeanDefinitionHolder. */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

/** List of names of manually registered singletons, in registration order. */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

其中可以看到跟BeanDefinition相关的成员变量有一下几个:

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

/** Map from bean name to merged BeanDefinitionHolder. */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

/** List of names of manually registered singletons, in registration order. */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

不言而喻,就是用来盛放BeanDefinition的,其中每种都有不同的用途!

三、Spring中内置的BeanDefinition

public AnnotationConfigApplicationContext() {
    super();
    // 额外会创建StandardEnvironment
    this.reader = new AnnotatedBeanDefinitionReader(this);
}

从第二行代码开始说起,进入到org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)方法中来

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		// .........

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		// 注册ConfigurationClassPostProcessor类型的BeanDefinition
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def,CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinition
		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));
		}

		// 注册CommonAnnotationBeanPostProcessor类型的BeanDefinition
		// 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));
		}

		// 注册PersistenceAnnotationBeanPostProcessor类型的BeanDefinition
		// 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));
		}
		// .........
		return beanDefs;
	}

首先Spring在这里内置了五个重要的BeanDefinition,但是其中有三个是常用且重要的BeanDefinition:ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

首先要来说明描述这三个BeanDefinition所能够起到的作用:

  • ConfigurationClassPostProcessor:①用来实现扫描配置类且注册到BeanDefinitionMap中去的;②用来实现对添加了@Configuration注解的类中的@Bean方法来进行解析的。(CGLIB实现一个类中的方法可以从容器中来获取得到对象);
  • AutowiredAnnotationBeanPostProcessor:①对类中的成员变量上添加了@Autowired注解的成员变量从容器中来进行获取;②对成员方法上添加了@Autowired注解的方法中的参数来从容器中来获取得到对应的值;
  • CommonAnnotationBeanPostProcessor:①对类中的成员变量上添加了@Resource注解的成员变量从容器中来进行获取;②对成员方法上添加了@Resource注解的方法中的参数来从容器中来获取得到对应的值;

那么分析上面三个中的一个即可!下面以ConfigurationClassPostProcessor来进行举例说明:

// 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinition
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));
}

①首先判断在BeanDefinitionMap中是否包含了key为org.springframework.context.annotation.internalConfigurationAnnotationProcessor名称的BeanDefinition,如果不包含,那么首先来进行创建对应类型的BeanDefinition;

②然后注册到put到beanDefinitionMap中去

第二步代码可以参考一下源代码:

// 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinition
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));
}

看一下注册代码:

private static BeanDefinitionHolder registerPostProcessor(
    BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // 注册关键信息:参数:beanName和对应的RootBeanDefinition
    registry.registerBeanDefinition(beanName, definition);  // BeanDefinitinoMap
    return new BeanDefinitionHolder(definition, beanName);
}

进入到org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition中来:

然后下面的方法分为以下几个步骤:

1、首先校验一下BeanDefinition是否是合法的

((AbstractBeanDefinition) beanDefinition).validate();

2、判断在beanDefinitionMap中是否已经存在?如果不存在,那么进行添加,走的是else逻辑:

// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);

放入到这两个集合(beanDefinitionMap和beanDefinitionNames)中来

四、注册配置类

直接来看三行代码中的第二行代码:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 这行代码
applicationContext.register(LiAppCOnfig.class);
applicationContext.refresh();

直接进去可以看到下面的代码:

this.reader.register(componentClasses);

这里的reader=new AnnotatedBeanDefinitionReader(this);,是在第一行代码中代码中进行创建的。

那么来看一下LiAppCOnfig这个类

@Configuration
@ComponentScan(basePackages = "com.guang")
public class LiAppCOnfig {}

这里有两个点:

①指定需要扫描的包。这个是一定要需要的,需要配置扫描包路径下面的类;

②声明当前类为配置类。这里的声明一定要存在的;

这里的this.reader = new AnnotatedBeanDefinitionReader(this);

那么看一下其中的register方法

private <T> void doRegisterBean(Class<T> beanClass,  String name,
                                 Class<? extends Annotation>[] qualifiers,Supplier<T> supplier,
                               BeanDefinitionCustomizer[] customizers) {

    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
        return;
    }

    abd.setInstanceSupplier(supplier);
    // 解析@Scope注解的结果为ScopeMetadata
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    // ............

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    // 注册配置类
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

①首先将对应的class来进行封装,封装成一个全新的AnnotatedGenericBeanDefinition,所以说启动类是有特殊含义的BeanDefinition;

②然后对当前配置类对应的BeanDefinition来进行封装解析;

③注册到beanDefinitionMap中去;

五、BeanDefinition总结

参考ProcessOn地址:https://www.processon.com/view/link/64c5f7d3b9f7806c73d7af0e

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/811282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Few Shot Classification小知识——数据集的加载

概述 Few-shot classification&#xff08;小样本分类&#xff09;是机器学习和人工智能的一个子领域&#xff0c;解决的问题是在训练数据非常有限的情况下&#xff0c;学习对新样本进行分类。在传统的监督学习中&#xff0c;模型需要在包含大量标记样本的数据集上进行训练&am…

Linux安装wget

1.第一步登录wget官网下载地址&#xff0c;下载最新的wget的rpm安装包到本地 官网地址&#xff1a;http://mirrors.163.com/centos/7/os/x86_64/Packages/ 2.将下载好的wget的rpm安装包通过Xftp工具上传到Linux服务器对应目录下。 3.cd命令进入到这个wget目录下&#xff0c;再…

【文献分享】动态环境下竟然能实现实时语义RGB-D SLAM??

论文题目&#xff1a;Towards Real-time Semantic RGB-D SLAM in Dynamic Environments 中文题目&#xff1a;动态环境下实时语义RGB-D SLAM研究 作者&#xff1a;Tete Ji, Chen Wang, and Lihua Xie 作者机构&#xff1a;新加坡南洋理工大学电气与电子工程学院 卡内基梅隆大…

用于WINDOWS的HACKRF ONE扫频分析仪

https://github.com/pavsa/hackrf-spectrum-analyzer GitHub - mutability/rtl-sdr: RTL-SDR *very* experimental branch - its probably broken! https://github.com/greatscottgadgets/hackrf hackrf_sweep 用于WINDOWS的HACKRF ONE扫频分析仪 几个星期前&#xff0c;Ha…

Java动态代理(全网最详细,没有之一)

首先你要明白为什么要创建代理&#xff1f;&#xff1f;&#xff1f; 例如&#xff1a;我们看下面这张图我们发现&#xff0c;有很多重复的代码&#xff0c;我们就可以创建代理&#xff0c;让代理帮我们干这些事情。 1.想要创建代理&#xff0c;我们就要为这个类写一个接口 pu…

无涯教程-jQuery - Menu组件函数

小部件菜单功能可与JqueryUI中的小部件一起使用。一个简单的菜单显示项目列表。 Menu - 语法 $( "#menu" ).menu(); Menu - 示例 以下是显示菜单用法的简单示例- <!doctype html> <html lang"en"><head><meta charset"utf-…

基于Linux操作系统中的MySQL数据库备份(三十三)

目录 一、概述 二、数据备份的重要性 三、造成数据丢失的原因 1、程序错误 2、人为错误 3、运算失败 4、磁盘故障 5、灾难&#xff08;如火灾、地震&#xff09;和盗窃 四、备份类型 &#xff08;一&#xff09;物理与逻辑角度 1、物理备份 1.1、冷备份 1.2、热备…

人工智能-Dlib+Python实现人脸识别(人脸识别篇)

人脸识别流程 人脸检测,人脸数据提取:首先是检测到人脸保存人脸数据:可以保存到mysql数据库中mysql数据库连接mysql数据库安装mysql数据库操作设置人脸数据标签:(人脸名字),保存到数据库打开摄像头,检测到人脸,提取人脸数据:人脸数据与数据库中的数据对比,1、人脸检…

子组件未抛出事件 父组件如何通过$refs监听子组件中数据的变化

我们平时开发项目会使用一些比较成熟的组件库, 但是在极小的情况下,可能会出现我们需要监听某个属性的变化,使我们的页面根据这个属性发生一些改变,但是偏偏组件库没有把这个属性抛出来,当我们使用watch通过refs监听时,由于生命周期的原因还不能拿到,这时候我们可以这样做,以下…

03-高阶导数_导数判断单调性_导数与极值

高阶导数 前面学的是一阶导数&#xff0c;对导数再次求导就是高阶导数&#xff0c;二阶和二阶以上的导数统称为高阶导数。 导数与函数单调性的关系 极值定理 导数为我们寻找极值提供依据&#xff0c;对于可导函数而言&#xff0c;因为在极值位置必然有函数的导数等于 0。 …

深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)模拟实现正反向迭代器【容器适配器模式】

深入篇【C】手搓模拟实现list类(详细剖析底层实现原理&#xff09;&& 模拟实现正反向迭代器【容器适配器模式】 Ⅰ.迭代器实现1.一个模板参数2.两个模板参数3.三个模板参数 Ⅱ.反向迭代器实现1.容器适配器模式 Ⅲ.list模拟实现1.定义结点2.封装结点3.构造/拷贝4.迭代器…

【Python】Web学习笔记_flask(1)——模拟登录

安装flask pip3 install flask 第一部分内容&#xff1a; 1、主页面输出hello world 2、根据不同用户名参数输出用户信息 3、模拟登录 from flask import Flask,url_for,redirectappFlask(__name__)app.route(/) def index():return hello worldapp.route(/user/<uname…

linux_进程状态

目录 一. 概念铺设 状态是什么&#xff1f; 传统操作系统的状态转换图 二. 传统操作系统状态 1. 运行 2. 阻塞 3. 挂起 三. linux 中的进程状态 1. 总体介绍 2. R 3. S 4. D kill -9 D vs S 5. T kill T vs S 6. Z 什么是僵尸状态&#xff1f; 僵尸进程的危害 …

hadoop部署配置

端口名称 Hadoop2.x Hadoop3.x NameNode内部通信端口 8020 / 9000 8020 / 9000/9820 NameNode HTTP UI 50070 9870 MapReduce查看执行任务端口 8088 8088 历史服务器通信端口 19888 19888 端口名称Hadoop2.xHadoop3.xNameNode内部通信端口8020 / 90008020 / 9000/9820NameNode…

延长周末,获得高质量休息:工作与学习党的生活策略

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【Linux】多线程的补充

1 线程安全的单例模式 1.1 什么是单例模式 单例模式是一种 "经典的, 常用的, 常考的" 设计模式. 1.2 什么是设计模式 IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些…

从源码角度配合网络编程函数API 分析下 三握手四挥手都做了什么

首先我们先说下网络编程API&#xff1a; 数据在网络上通信&#xff0c;通信的双方一个是 客户端&#xff0c; 一个是 服务器 更具体来说&#xff0c;不是 客户端和服务器这两个机器在 经由互联网 进行通信&#xff0c; 而是 客户端上的某一进程 与 服务器端的某一进程 进…

Vue2 第七节 Vue监测数据更新原理

&#xff08;1&#xff09;Vue会监视data中所有层次的数据 &#xff08;2&#xff09;如何监测对象中的数据 通过setter实现监视&#xff0c;且要在new Vue时传入要监测的数据对象中后追加的属性&#xff0c;Vue默认不做响应式处理如果要给后添加的属性做响应式&#xff0c;使…

【笔记】PyTorch DDP 与 Ring-AllReduce

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 文内若有错误&#xff0c;欢迎指出&#xff01; 今天我想跟大家分享的是一篇虽然有点老&#xff0c;但是很经典的文章&#xff0c;这是一个在分布式训练中会用到的一项技术&#xff0c; 实际上叫ringallreduce。 …

Hyper-v 设置静态IP 搭建集群

背景 最近想在本机WIN11上创建几个Centos用于做几个试验&#xff0c;之前一直用VMWare&#xff0c;需要安装额外的软件&#xff0c;正好win自带虚拟机功能&#xff0c;只需要在功能中安装Hyper-v就可以使用。 新建虚拟机 虚拟机交换器 Hyper-V 虚拟交换机是基于软件的第 2 层…