Spring之BeanDefinition(三)

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 对象的生存期

对象&#xff08;包括简单变量&#xff09;都有诞生和消失的时刻。对象诞生到结束的这段时间就是它的生存期。在生存期内&#xff0c;对象将保持它的状态&#xff08;即数据成员的值&#xff09;&#xff0c;变量也将保持它的值不变&#xff0c;直到它们被更新为止。对象的生存…

城市内涝 | 复杂城市排水管网系统快速建模、管网水力性能专题图制作、城市内涝一维二维耦合模拟、海绵城市关键控制指标计算

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本次培训将聚焦于综合利用GIS及CAD等工具高效地进行大规模城市排水系统水力模型的建立&#xff0c;利用SWMM实现排水系统水力模拟。讲解…

微信小程序(van-tabs) 去除横向滚动条样式(附加源码解决方案+报错图)

问题描述 今天第一次接触vant组件库。 ant官网地址适用于Vue3 支持Vue2、Vue3、微信小程序等 我在使用van-tabs组件时遇到了一个问题&#xff0c;如下图所示&#xff1a; 从图片上可以看到有个灰色的横向滚动条&#xff0c;一开始领导给我说这个问题&#xff0c;我反反复复都…

mybatisJava对象、list和json转换

1. 参考mybatis-plus mybatis Java对象、list和json转换 网上好多不靠谱&#xff0c;参考mybatis-plus中TableField&#xff0c;mybatis中自定义实现 这样不需要对象中属性字符串接收&#xff0c;保存到表中&#xff0c;都是转义字符&#xff0c;使用时还要手动转换为对象或者…

IOS + Appium自动化教程

前言 项目闲置下来了&#xff0c;终于抽空有时间搞自动化了&#xff0c;看了下网上的教程基本通篇都是android自动化的介绍 &#xff0c;ios自动化方面的内容网上简介的少之可怜。由于本人对ios自动化也是第一次做&#xff0c;甚至对苹果电脑的使用都不太熟悉&#xff0c;花了大…

51:电机(ULN2003D)

1:介绍 我们51单片机使用的是直流电机 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&#xff08;转…

功率放大器的种类有哪三种类型

功率放大器是一种能将输入信号转换为更高功率输出的电子设备。在电子工程和音频领域中&#xff0c;功率放大器通常被分为三种类型&#xff1a;A类、B类和AB类。下面安泰电子将详细介绍这三种类型的功率放大器及其特点。 A类功率放大器 A类功率放大器是一种基本的线性功率放大器…

C++内存管理(动态内存开辟)

我们在C语言当中想要使用堆区的空间的时候就需要使用malloc函数进行手动的申请&#xff0c;但是我们在申请的时候需要手动进行计算&#xff0c;经过计算之后还需要进行判空操作&#xff0c;并且还不能进行任意值的初始化。这一切看起来在学习完C当中的动态开辟之前显得很正常&a…

Pytorch个人学习记录总结 10

目录 优化器 优化器 官方文档地址&#xff1a;torch.optimhttps://pytorch.org/docs/stable/optim.html Debug过程中查看的grad所在的位置&#xff1a; model --> Protected Atributes --> _modules --> ‘model’ --> Protected Atributes --> _modules -…

【PostgreSQL】系列之 一 CentOS 7安装PGSQL15版本(一)

目录 一、何为PostgreSQL&#xff1f; 二、PostgreSQL安装 2.1安装依赖 2.2 执行安装 2.3 数据库初始化 2.4 配置环境变量 2.5 创建数据库 2.6 配置远程 2.7 测试远程 三、常用命令 四、用户创建和数据库权限 一、何为PostgreSQL&#xff1f; PostgreSQL是以加州大学…

MacOS Monterey VM Install ESXi to 7 U2

一、MacOS Monterey ISO 准备 1.1 下载macOS Monterey 下载&#x1f517;链接 一定是 ISO 格式的&#xff0c;其他格式不适用&#xff1a; https://www.mediafire.com/file/4fcx0aeoehmbnmp/macOSMontereybyTechrechard.com.iso/file 1.2 将 Monterey ISO 文件上传到数据…

shell清理redis模糊匹配的多个key

#!/bin/bash# 定义Redis服务器地址和端口 REDIS_HOST"localhost" REDIS_PORT6380# 获取匹配键的数量 function get_matching_keys() {local key_pattern"$1"redis-cli -h $REDIS_HOST -p $REDIS_PORT -n 0 KEYS "$key_pattern" }# 删除匹配的键 …

java+springboot+mysql企业邮件管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的企业邮件管理系统&#xff0c;系统包含超级管理员、管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;员工管理&#xff1b;反馈管理&#xff1b;系统公告&#xff1b;个人…

【Linux学习】日积月累——进程控制

一、进程创建 1.1 fork函数的认识 #include<unistd.h> pid_t fork(void); 返回值&#xff1a;自进程返回0&#xff0c;父进程返回子进程PID&#xff0c;出错返回-1进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核做&#xff1a;分配新的内存块…

Linux ALSA音频工具aplay、arecord、amixer的使用方法

ALSA 是Advanced Linux Sound Architecture的缩写&#xff0c;先进的Linux音频架构&#xff0c;为Linux操作系统提供音频和MIDI功能。 aplay命令 aplay是播放命令。 rootimx6ul7d:~# aplay -h Usage: aplay [OPTION]... [FILE]...-h, --help help--version …

解决Hadoop审计日志hdfs-audit.log过大的问题

【背景】 新搭建的Hadoop环境没怎么用&#xff0c;就一个环境天天空跑&#xff0c;结果今天运维告诉我说有一台服务器磁盘超过80%了&#xff0c;真是太奇怪了&#xff0c;平台上就跑了几个spark测试程序&#xff0c;哪来的数据呢&#xff1f; 【问题调查】 既然是磁盘写满了&…

浅谈微服务异步解决方案

导言 异步是一种设计思想&#xff0c;不是设计目的&#xff0c;因此不要为了异步而异步&#xff0c;要有所为&#xff0c;有所不为。 异步不是『银弹』&#xff0c; 避免试图套用一个『异步框架』解决所有问题&#xff0c; 需要根据不同的业务特点或要求&#xff0c;选择合适的…

VSCode自定义闪烁光标

打开VSCode 组合键ctrlshiftp搜索"settings.json",打开User Settings 加上这一句 "editor.cursorStyle": "block","workbench.colorCustomizations": {"editorCursor.foreground": "#5c8fb1","terminalCurs…

IDEA中Git面板操作介绍 变基、合并、提取、拉取、签出

IDEA中Git面板操作介绍 变基、合并、提取、拉取、签出 面板介绍 变基、合并 提取、拉取 签出、Checkout 面板介绍 如图&#xff0c;在IDEA的Git面板中&#xff0c;仓库会分为本地仓库和远程仓库&#xff0c;代码仓库里面放的是各个分支。 分支前面的书签&#x1f516;标志…

JavaScript高级——ES6基础入门

目录 前言let 和 const块级作用域模板字符串一.模板字符串是什么二.模板字符串的注意事项三. 模板字符串的应用 箭头函数一.箭头函数是什么二.普通函数与箭头函数的转换三.this指向1. 全局作用域中的 this 指向2. 一般函数&#xff08;非箭头函数&#xff09;中的this指向3.箭头…