iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Spring Bean中Bean的注册是什么
  • 344
分享到

Spring Bean中Bean的注册是什么

2023-06-29 09:06:23 344人浏览 安东尼
摘要

这篇文章主要介绍“spring Bean中Bean的注册是什么”,在日常操作中,相信很多人在Spring Bean中Bean的注册是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spr

这篇文章主要介绍“spring Bean中Bean的注册是什么”,在日常操作中,相信很多人在Spring Bean中Bean的注册是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spring Bean中Bean的注册是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

前言

这里主要围绕BeanDefinitionReaderUtils#reGISterBeanDefinition展开分析下Bean注册过程

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);}}}

上面无论是注册bd还是建立alias-beanName之间的关系,均用到了BeanDefinitionRegistry,因此我们就以它为突破口来展开

BeanFactory的继承体系

Spring Bean中Bean的注册是什么

对图中常用接口或类进行说明:

  • ListableBeanFactory 集合类型BeanFactory 提供一种可以查找所有Bean实例的能力

    • getBeanNamesForType(Class) 根据类型去查找Bean名称列表不会强制Bean的初始化,可从源码中看出来

    • getBeansOfType(Class) 根据类型去查找Bean实例列表,会强制Bean的初始化,可从源码中看出来

    • getBeanNamesForAnnotation(Class) 根据注解类型获取Bean名称列表

    • getBeansWithAnnotation(Class) 根据注解类型获取Bean实例列表

    • findAnnotationOnBean(String,Class) 根据指定名称+标注类型获取Bean实例

  • Hierarchical([ˌhaɪəˈrɑːkɪkl])BeanFactory 层次性BeanFactory,有父子容器的概念,可在ConfigurableListableBeanFactory设置其父容器

    • getParentBeanFactory() 获取父容器

    • boolean containsLocalBean(String name) 在当前容器中查找是否存在该名称的Bean实例

  • SingletonBeanRegistry 单实例BeanFactory,与单实例有关

  • ConfigurableBeanFactory 可配置的BeanFactory,这个一般不用于应用程序,是给其他BeanFactory扩展用的。的确,定义了很多配置方法

  • ConfigurableListableBeanFactory 可配置的集合类型的BeanFactory

  • AutowireCapableBeanFactory 提供具有自动装配能力的BeanFactory

透过继承体系可以看出,BeanDefinitionRegistry的实现类是DefaultListableBeanFactory,该类同时实现了诸多接口,可谓是BeanFactory中集大成者,因此我们到DefaultListableBeanFactory中阅读下bd注册及别名注册的源码

Bean的注册

先来分析下DefaultListableBeanFactory的几个重要的成员属性

// 这个实质上就是ioc容器中Bean的载体,没错 它很重要,但它是无序的private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);//它代表了bd名称的集合,它是有序的 遵循bd注册的顺序private volatile List<String> beanDefinitionNames = new ArrayList<>(256);// 这是已创建bd名称的集合,在doGetBean方法根据beanName创建Bean时,beanName会被加到此集合中private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

上面两个属性都比较重要,两者结合使用的话可以实现bd的顺序访问(其实就是遍历beanDefinitionNames集合时,使用beanDefinitionMap去获取bd)

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {//对beanName、bd进行非空验证Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");//如果bd是AbstractBeanDefinition类型,则对bd进行验证(一般情况下 我们场景的bd都是继承自AbstractBeanDefinition的)if (beanDefinition instanceof AbstractBeanDefinition) {try {   //bd验证((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {//省略异常代码}}//从beanDefinitionMap根据beanName取bdBeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);//如果beanName名称的bd已经存在if (existingDefinition != null) {//如果不允许Bean被重新注册 则抛出异常,这里默认值是trueif (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}//如果已被注册bd的角色值小于当前待注册bd的角色值 else if (existingDefinition.getRole() < beanDefinition.getRole()) {// 省略日志输出}//如果已注册的同名bd 与本次注册的bd不相同else if (!beanDefinition.equals(existingDefinition)) {//省略日志输出}else {//省略日志输出}//将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);}else {//流程走到这里 说明在beanDefinitionMap中不存在同名bd//条件成立 说明alreadyCreated不为空 即有bd已被创建if (hasBeanCreationStarted()) {// 如果在此之间 有bean正在被创建 则这里进行加处理synchronized (this.beanDefinitionMap) {    //将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);//将beanName添加到beanDefinitionNames集合中List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;//如果beanName是手动注册的单例Bean名称,则更新manualSingletonNamesif (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);//这里从集合中删除的原因个人理解://manualSingletonNames记录的是在registerSingleton时被添加的单实例beanName,而这里注入的不是单实例Bean。因为manualSingletonNames包含了此beanName,因此需要剔除updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;}}}else {//如果没有bean在被创建//将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);//将beanName添加到集合中this.beanDefinitionNames.add(beanName);//这里从manualSingletonNames中剔除,个人理解为拖地操作,毕竟若集合中没有此beanName 也remove不了this.manualSingletonNames.remove(beanName);}//这个集合表示冻结配置时缓存的beanName集合,暂时未理解透此集合的用途this.frozenBeanDefinitionNames = null;}//如果已存在同名bd或已存在同名的单例对象,则重置所有已被缓存的同名的bd数据,因此这里bd注册成功后,肯定后续还会再生成Bean的if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);}}

其实分析下来发现Bean注册的过程还是比较容易理解的,下面试总结一下:

  • 若bd未被注册过,则将bd信息存入BeanDefinitionMap等集合中

  • 若bd已被注册过,允许覆盖注册的情况下,将bd信息存入BeanDefinitionMap等集合中,并清除已被缓存的同名bd信息

下面看一下清除bd信息的代码逻辑

protected void resetBeanDefinition(String beanName) {// 如果此bd属于被合并的BeanDefinition,则这里将其从MergeBeanDefinition集合中剔除clearMergedBeanDefinition(beanName);// 如果已存在同名的单例对象 则销毁,具体细节先不展开destroySingleton(beanName);// 这里for循环逻辑与MergeBeanDefinition相关,如果存在MergedBeanDefinitionPostProcessor,则重置此bdfor (BeanPostProcessor processor : getBeanPostProcessors()) {if (processor instanceof MergedBeanDefinitionPostProcessor) {((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);}}// BeanDefinition运行有层级的,如果此bd拥有多个父级bd,那么这里递归地重置其父bdfor (String bdName : this.beanDefinitionNames) {if (!beanName.equals(bdName)) {BeanDefinition bd = this.beanDefinitionMap.get(bdName);if (beanName.equals(bd.getParentName())) {resetBeanDefinition(bdName);}}}}

alias别名的注册

看了Bean的注册,再来看别名的注册 发现流程比较清晰,基本上一目了然。

//注意 这里的name 不要具象为beanName,虽然我们是从建立beanName--alias关系出发追溯到这里的public void registerAlias(String name, String alias) {//对name、alias进行断言验证Assert.hasText(name, "'name' must not be empty");Assert.hasText(alias, "'alias' must not be empty");synchronized (this.aliasMap) {//如果别名与beanName相同,那别名就没有必要存在了,因此选择直接从this.aliasMap中移除此别名if (alias.equals(name)) {this.aliasMap.remove(alias);//省略日志输出}else {   //从aliasMap中根据别名获取nameString registeredName = this.aliasMap.get(alias);if (registeredName != null) {    //如果已存在的registeredName与此此要注册的name一致,那就没必要注册了if (registeredName.equals(name)) {return;}//流程走到这里,说明同一个别名,对应两个name,如果不允许alias覆盖 则抛出异常if (!allowAliasOverriding()) {//省略异常及日志输出}//这里对alias进行循环检查,避免出现A的别名是B,B的别名是A的情况checkForAliasCircle(name, alias);//将alias--name 放入aliasMapthis.aliasMap.put(alias, name);//省略日志输出}}}

alias与beanName的映射关系,为根据名称查找Bean又提供了一种思路。就是说除了根据beanName外,也可以根据alias去查找Bean。

这部分源码如下

//name可以是beanName,也可以是aliaspublic String canonicalName(String name) {//局部变量赋值String canonicalName = name;// Handle aliasing...String resolvedName;do {    //如果从aliasMap中能根据alias分析出beanNameresolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);// 无论入参name是beanName还是alias,这里返回的都应该是beanName了return canonicalName;}

到此,关于“Spring Bean中Bean的注册是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Spring Bean中Bean的注册是什么

本文链接: https://www.lsjlt.com/news/323979.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring Bean中Bean的注册是什么
    这篇文章主要介绍“Spring Bean中Bean的注册是什么”,在日常操作中,相信很多人在Spring Bean中Bean的注册是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spr...
    99+
    2023-06-29
  • 怎么动态注册Bean到Spring
    这篇文章主要介绍了怎么动态注册Bean到Spring的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么动态注册Bean到Spring文章都会有所收获,下面我们一起来看看吧。1、理论一般如果想将类注册到sprin...
    99+
    2023-06-29
  • Spring中bean集合注入的方法是什么
    这篇文章主要讲解了“Spring中bean集合注入的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring中bean集合注入的方法是什么”吧!Spring作为项目中不可缺少的底...
    99+
    2023-07-02
  • Spring中的bean概念是什么
    这篇文章将为大家详细讲解有关Spring中的bean概念是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Bean是Spring框架中最核心的两个概念之一(另一个是面向切面编程AOP)。1 定义Spri...
    99+
    2023-06-29
  • 向Spring IOC容器动态注册bean实现方式是什么
    本篇内容主要讲解“向Spring IOC容器动态注册bean实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“向Spring IOC容器动态注册bean实现方式是什...
    99+
    2023-07-02
  • Spring @Bean注解的使用场景是什么
    本篇内容介绍了“Spring @Bean注解的使用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、简单介绍翻看Spri...
    99+
    2023-07-05
  • Spring IOC源码之bean的注册过程讲解
    目录BeanDefition加载注册过程进入obtainFreshBeanFactory方法​进入AbstractRefreshableApplicationContex...
    99+
    2022-11-12
  • Spring中的Bean作用域是什么
    本文小编为大家详细介绍“Spring中的Bean作用域是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring中的Bean作用域是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。概述scope用来声明...
    99+
    2023-06-30
  • Spring中Bean的作用域是什么
    这篇文章给大家介绍Spring中Bean的作用域是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、Bean的作用域首先我们来讲一下有关于bean的作用域,一般情况下,我们书写在IOC容器中的配置信息,会在我们的I...
    99+
    2023-06-20
  • Spring注解@Configuration与@Bean注册组件的使用详解
    目录原始Spring开发Person.javapom.xmlbean.xmlPersonTest.java注解Spring开发原始Spring开发 Person.java 准备Per...
    99+
    2022-11-13
  • spring中怎么向一个单例bean中注入非单例bean
    这篇文章主要介绍“spring中怎么向一个单例bean中注入非单例bean”,在日常操作中,相信很多人在spring中怎么向一个单例bean中注入非单例bean问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”s...
    99+
    2023-06-20
  • Spring的@Bean注解怎么使用
    今天小编给大家分享一下Spring的@Bean注解怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Spring @Be...
    99+
    2023-07-02
  • Spring bean需要依赖注入的原因是什么
    这篇文章主要介绍“Spring bean需要依赖注入的原因是什么”,在日常操作中,相信很多人在Spring bean需要依赖注入的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spring bean...
    99+
    2023-06-20
  • spring中bean的生命周期是什么
    在Spring中,Bean的生命周期包括以下几个阶段:1. 实例化:当Spring容器接收到请求时,根据配置文件或注解等方式,在内存...
    99+
    2023-09-27
    spring bean
  • Spring中Bean扫描原理是什么
    本篇内容主要讲解“Spring中Bean扫描原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring中Bean扫描原理是什么”吧!环境建设由于创建包扫描的条件很简单,只要在Xml中配...
    99+
    2023-07-02
  • Spring bean为什么需要依赖注入
    目录具体步骤:样例1:样例2:Spring单例模式和原型模式一、单例模式二、原型模式思考 为什么需要依赖注入总结具体步骤: 1.创建一个maven项目 spring-day1-con...
    99+
    2022-11-12
  • Spring 中存取 Bean 的相关注解
      目录  一、五大类注解 1、五大类注解存储Bean对象 1.1@Controller(控制器储存) 1.2@Service(服务存储) 1.3@Repository(仓库存储) 1.4@Component(组件存储) ...
    99+
    2023-09-21
    spring java 后端
  • Spring中动态注入Bean的方法
    这篇文章将为大家详细讲解有关Spring中动态注入Bean的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、基于标注的方式注入实例需要在Bean初始化之时,其依赖的对象必须初始化完毕。如果被注入的对...
    99+
    2023-05-30
    spring bean
  • spring中@Configuration和@Bean注解的用法
    目录概要定义注意概要 @Configuration里边定义@Bean,@Configuration相当于一个xml配置文件,@Bean就是xml中的<bean/> 定义 ...
    99+
    2023-05-20
    spring @Configuration spring @Bean spring注解
  • Spring Bean的生命周期是什么
    这篇“Spring Bean的生命周期是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring ...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作