解析 Spring 框架中的三种 BeanName 生成策略
在 Spring 框架中,定义 Bean 时不一定需要指定名称,Spring 会智能生成默认名称。本文将介绍 Spring 的三种 BeanName 生成器,包括在 XML 配置、Java 注解和组件扫描中使用的情况,并解释它们如何自动创建和管理 Bean 名称。
1. BeanNameGenerator
Spring 中提供了一个名为 BeanNameGenerator 的接口,这个接口就只有一个需要实现的方法就是 generateBeanName,从名字就能看出来,这就是专门用来生成 beanName 的方法。
public interface BeanNameGenerator {String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
这个方法有两个参数:
- definition:这个是要生成的 Bean 定义。
- registry:这个是将来 BeanDefinition 的注册器。
BeanNameGenerator 有三个不同的实现类,对应不同的处理场景:

- AnnotationBeanNameGenerator:这个专门用来处理包扫描的时候扫到的 Bean,对于这些 Bean,其 name 属性该如何处理,由这个类来解决,当然,小伙伴们都知道,通过 @Component/@Service/@Repository/
@Controller 这些注解定义的 Bean,默认情况下,beanName 就是类名首字母小写。 - FullyQualifiedAnnotationBeanNameGenerator:这个继承自 AnnotationBeanNameGenerator,并重写了 AnnotationBeanNameGenerator#buildDefaultBeanName 方法,这个是使用类的全路径来作为 Bean 的默认名称。
- DefaultBeanNameGenerator:这个是专门用来解决 XML 文件中定义的 Bean 如果没有设置 beanName,那么就通过 DefaultBeanNameGenerator 来为其生成 beanName。
看了上面三个场景之后,可能有小伙伴发现一个 BUG,那么
注解定义的 Bean,其 beanName 属性是在哪里处理的呢?这个其实比较特殊,是当场处理的,没用到 BeanNameGenerator,松哥后面单独说。
接下来我们详细看下上面这三个实现类。
2. AnnotationBeanNameGenerator
咱们直接来看最关键的 generateBeanName 方法吧:
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {// Explicit bean name found.return beanName;}}// Fallback: generate a unique default bean name.return buildDefaultBeanName(definition, registry);
}
这个方法首先判断 definition 是否为 AnnotatedBeanDefinition 类型,根据我们前面文章对 BeanDefinition 的介绍,大家知道,AnnotatedBeanDefinition 的实现类主要是针对三种情况:@Bean 注解定义的 Bean、@Service/@Controller/@Component/@Repository 等注解标记的 Bean 以及系统的启动配置类,如果是这三种情况,那么就去调用 determineBeanNameFromAnnotation 方法,这个方法会尝试从注解中提取出来 beanName,如果不是上面三种情况,那么就调用 buildDefaultBeanName 方法去生成 beanName。
那我们先来看 determineBeanNameFromAnnotation 方法:
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {AnnotationMetadata amd = annotatedDef.getMetadata();Set<string> types = amd.getAnnotationTypes();String beanName = null;for (String type : types) {AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);if (attributes != null) {Set<string> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {Set<string> result = amd.getMetaAnnotationTypes(key);return (result.isEmpty() ? Collections.emptySet() : result);});if (isStereotypeWithNameValue(type, metaTypes, attributes)) {Object value = attributes.get("value");if (value instanceof String strVal) {if (StringUtils.hasLength(strVal)) {if (beanName != null && !strVal.equals(beanName)) {throw new IllegalStateException("Stereotype annotations suggest inconsistent " +"component names: '" + beanName + "' versus '" + strVal + "'");}beanName = strVal;}}}}}return beanName;
}
这个方法首先会去获取类上的注解信息,拿到 amd 之后,获取到所有的注解类型,然后进行遍历。
遍历的时候,首先获取到注解上的所有属性 attributes,当 attributes 不为空的时候,继续去读取当前注解的元注解,并将读取到的结果存入到 metaAnnotationTypesCache 集合中。这个是干嘛呢?大家知道,Spring 中用来标记 Bean 的注解大部分衍生自 @Component,甚至我们也可以自定义注解,那么如果自定义注解了,这个地方就没法判断了,因为每个人自定义出来的注解都不一样。所以,万变不离其宗,这里就去找各个注解的元注解。例如如果我们在类上添加的是 @Configuration,那么 @Configuration 的元注解有两个,分别是 @Component 和 @Indexed。
接下来的 isStereotypeWithNameValue 方法就是判断 type 是不是 @Component 或者 Jakarta 中自带的 @ManagedBean、@Named,亦或者 metaTypes 里是否包含 @Component。如果确定是 @Component 衍生出来的注解,亦或者是 @ManagedBean、@Named 注解标记的 Bean,那么就将其 value 属性读取出来,作为 beanName,如果包含多个有效注解,且各自配置的 beanName 不一致,就会抛出异常。
例如下面这种情况:
@Configuration("j")
@Component("a")
public class JavaConfig {
}
这两个 beanName 不一致,运行时就会出错。
同时,经过上面的分析,小伙伴也看到了,我们其实可以通过自定义注解为 Bean 设置名称,例如我有如下注解:
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyBeanName {String value() default "";
}
这个注解衍生自 @Component,那么它的用法如下:
@MyBeanName("f")
public class JavaConfig {}
那么 f 就是当前类生成的 beanName。
以上是从注解中去提取 beanName,但是注解中可能没有提供 beanName,那么就得调用 buildDefaultBeanName 方法去自动生成了,如下:
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return buildDefaultBeanName(definition);
}
protected String buildDefaultBeanName(BeanDefinition definition) {String beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");String shortClassName = ClassUtils.getShortName(beanClassName);return StringUtils.uncapitalizeAsProperty(shortClassName);
}
这个就很好懂了,先拿到 bean 的完整类名,然后提取出来 shortName,也就是去除包名之后的名字,然后首字母小写之后返回。
这就是 @Component 注解体系下的 beanName 生成流程。
3. FullyQualifiedAnnotationBeanNameGenerator
FullyQualifiedAnnotationBeanNameGenerator 类只是重写了 AnnotationBeanNameGenerator 的 buildDefaultBeanName 方法,如下:
@Override
protected String buildDefaultBeanName(BeanDefinition definition) {String beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");return beanClassName;
}
重写后的方法就是获取类的完整路径返回。
FullyQualifiedAnnotationBeanNameGenerator 默认情况下并不会直接使用,需要自己手动配置,像下面这样:
@Configuration
@ComponentScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class JavaConfig {}
此时,生成的 Bean 的默认名称就是类的全路径了。
4. DefaultBeanNameGenerator
这个是专门用来处理 XML 中默认的 beanName 的。这个在最近录制的 Spring 源码视频中已经详细介绍过了,这里就不再啰嗦了。。
5. @Bean 处理特殊情况
如果类是被 @Bean 注解标记的,那么处理情况就特殊一些,直接现场处理,方法在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod 位置:
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {// Consider name and any aliasesList<string> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));String beanName = (!names.isEmpty() ? names.remove(0) : methodName);// Register aliases even when overriddenfor (String alias : names) {this.registry.registerAlias(beanName, alias);}
}
从这里可以看到,如果一开始配置了 name 属性,那么就把 names 集合中的第一个值拿出来作为 beanName,集合中的其他值则当作别名来处理,如果没有配置 name 属性值,那么就使用方法名作为 beanName。
相关文章:
解析 Spring 框架中的三种 BeanName 生成策略
在 Spring 框架中,定义 Bean 时不一定需要指定名称,Spring 会智能生成默认名称。本文将介绍 Spring 的三种 BeanName 生成器,包括在 XML 配置、Java 注解和组件扫描中使用的情况,并解释它们如何自动创建和管理 Bean 名称。 1. Be…...
细说ARM MCU的串口接收数据的实现过程
目录 一、硬件及工程 1、硬件 2、软件目的 3、创建.ioc工程 二、 代码修改 1、串口初始化函数MX_USART2_UART_Init() (1)MX_USART2_UART_Init()串口参数初始化函数 (2)HAL_UART_MspInit()串口功能模块初始化函数 2、串口…...
000-基于sklearn的机器学习入门:工作环境搭建与配置
本专栏将介绍基于Scikit-learn(简称sklearn)的机器学习入门知识。包括但不一定限于,机器学习基本知识、sklearn库简介,基于Sklearn库的机器学习实践。 这是本专栏的第000篇,将介绍如何安装和配置sklearn环境,不仅包括Sklearn库的…...
就业班 第四阶段(k8s) 2401--6.5 day3 Yaml语法解析+钩子函数
Yaml语法解析 今天学的都是在pod里面操作的 格式 这个文件要创建的资源对象是什么 kind: Pod 这个资源对象所在的api版本是什么 apiVersion: v1 元数据 metadata: 对这个pod中的镜像的描述 spec: 字典无序 同一级可以调换顺序 :比如kind和apiVersion …...
电脑开机出现英文字母,如何解决这个常见问题?
电脑开机时出现英文字母的情况通常意味着系统在启动过程中遇到了问题。这些英文字母可能是错误信息、系统提示或BIOS设置问题。通过理解这些信息并采取适当的措施,您可以解决大多数启动问题。本文将介绍三种解决电脑开机出现英文字母问题的方法,帮助您恢…...
一张试卷
目录 问题 1: 1.时间 题目描述1 输入1 输出1 样例输入1 样例输出1 提示1 代码1 问题 2: 超酷的电话号码 题目描述2 输入2 输出2 样例输入2 样例输出2 提示2 代码2 问题 3:3.爸爸的数学题 题目描述3 输入3 输出3 样例输入3 样例输出3 提示3 代码3 问题 4: 4. 营养膳食 题目描述4…...
记一次 .NET某游戏币自助机后端 内存暴涨分析
一:背景 1. 讲故事 前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机…...
计算机考研|哪些985/211院校不歧视双非二本生?
说句残酷的话,能对某一专业做出贡献,那么你的水平肯定是很高的。如果普通学生,普通本科的话可能很难做到这一点。这也是现在考研风气比较强的原因,一部分专业能力不突出的学生来选择深造3年。 对于基础较差想要考计算机研究生的同…...
Spring Boot:简化 Java 应用开发的艺术
Spring Boot 是一种用于快速开发、运行和管理 Java 应用程序的开源框架。它简化了基于 Spring 的应用程序的配置和部署,使得开发者能够更加专注于业务逻辑的实现。本文将介绍 Spring Boot 的核心特性、优势以及如何在项目中使用 Spring Boot。 一、核心特性 自动配…...
elasticsearch安装与使用(2)-基于term匹配的简单搜索引擎搭建
把一篇pdf论文解析后,放入es数据库中,建立倒排索引表,并实现简单搜索。 1、pdf论文解析(英文) 安装pdf解析包 pip install pdfminer.sixdef extract_text_from_pdf(filename, page_numbersNone, min_line_length1):从pdf文件中提取文字:pa…...
速盾:ddos防护与高防ip区别?
在网络安全领域,DDOS 防护和高防 IP 都是重要的防护手段,但它们之间存在着一些明显的区别。 DDOS 防护是一种针对分布式拒绝服务攻击的防御策略。它通过多种技术和方法来识别和抵御 DDOS 攻击。常见的 DDOS 防护手段包括流量清洗、连接限制、协议分析等。…...
Java中StringBulider详解
StringBuilder 是 Java 中一个用来创建可变字符串的类。与 String 类不同,StringBuilder 对象能够被修改,不会创建新的对象,因此在需要进行大量字符串操作时,StringBuilder 更高效。以下是 StringBuilder 的详细讲解。 创建 Stri…...
基于springboot高校就业招聘系统的设计
管理员账户功能包括:系统首页,个人中心,就业咨询管理,毕业去向管理,简历管理,管理员管理,基础数据管理 辅导员账户功能包括:系统首页,个人中心,就业咨询管理…...
嵌入式C语言编码规范要点
1.函数命名方法 骆驼命名法(Camel) 帕斯卡命名法((pascal),也叫大驼峰命名法(Upper Camel Case) 匈牙利命名法 下划线命名法(也称为蛇形命名法) 详述见之前文…...
Python中的全局解释器锁:深入解析与应对策略
1. 引言 在Python的世界里,全局解释器锁(GIL)是一个经常被讨论的话题。它既是Python并发编程中的一个重要概念,也是许多开发者感到困惑的源头。本文将深入探讨GIL的工作原理、它对Python程序性能的影响 2. 全局解释器锁的历史背…...
【java计算机毕设】图书商城管理系统MySQL springboot vue html maven送文档
1项目功能介绍 【java计算机毕设】图书商城管理系统 Java Spring Boot vue HTML MySQL 赠送文档 PPT 2项目简介 系统功能: 图书商城管理系统包括管理员和用户两种角色。 管理员的功能包括在个人中心修改个人信息,以及在基础数据管理中管理会员等级类型和…...
【Java刷题】二叉树
相同的树 public boolean isSameTree(TreeNode p, TreeNode q) {if(p null && q null) {return true;} else if(p ! null && q ! null) {if(p.val ! q.val) {return false;} else {return isSameTree(p.left, q.left) && isSameTree(p.right, q.rig…...
【Linux】程序地址空间之动态库的加载
我们先进行一个整体轮廓的了解,随后在深入理解细节。 在动态库加载之前还要说一下程序的加载,因为理解了程序的加载对动态库会有更深的理解。 轮廓: 首先,不管是程序还是动态库刚开始都是在磁盘中的,想要执行对应的可…...
LabVIEW处理大量数据时,怎样确保数据的准确性和完整性?
在LabVIEW处理中,确保大量数据的准确性和完整性至关重要。以下是详细的多角度分析和建议,以确保在LabVIEW中处理大量数据时,数据的准确性和完整性: 1. 数据采集阶段 1.1 高精度硬件选择 选择高精度的数据采集硬件,如…...
容器是什么?
概念 容器可以被看作是一种轻量级的虚拟化技术。与传统虚拟化技术相比,容器不需要为每个应用程序提供单独的操作系统,它们共享宿主机的操作系统内核。这使得容器更加轻便和高效。 想象一下,容器就像是一艘艘可以在海洋中独立航行的货轮&…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
