目录

1、BeanNameGenerator 接口

2、AnnotationBeanNameGenerator 类

3、DefaultBeanNameGenerator 类


spring容器是通过bean Name去管理着大量的bean,而且不出错。

首先看看spring是如何为每个bean生成名字的,BeanNameGenerator接口是bean名字生成器的入口,下面是类图:

1、BeanNameGenerator 接口

就一个方法,为某个bean生成名字,参数为BeanDefinition 和 BeanDefinitionRegistry 类型。此处可以反映出spring需要的bean结构是BeanDefinition。

public interface BeanNameGenerator {String generateBeanName(BeanDefinition var1, BeanDefinitionRegistry var2);
}

2、AnnotationBeanNameGenerator 类

从这个类名基本可以知道,这个类是为那些用注解方式的bean生成名字。暂时不作介绍。

public class AnnotationBeanNameGenerator implements BeanNameGenerator {//@Component注解(这个功能类)的类名private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";public AnnotationBeanNameGenerator() { }//生成bean的名字,实现了接口中的方法public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {String beanName = this.determineBeanNameFromAnnotation((AnnotatedBeanDefinition)definition);if (StringUtils.hasText(beanName)) {return beanName;}}return this.buildDefaultBeanName(definition, registry);}@Nullableprotected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {AnnotationMetadata amd = annotatedDef.getMetadata();Set<String> types = amd.getAnnotationTypes();String beanName = null;Iterator var5 = types.iterator();while(var5.hasNext()) {String type = (String)var5.next();AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);if (attributes != null && this.isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {Object value = attributes.get("value");if (value instanceof String) {String strVal = (String)value;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;}protected boolean isStereotypeWithNameValue(String annotationType, Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {boolean isStereotype = annotationType.equals("org.springframework.stereotype.Component") || metaAnnotationTypes.contains("org.springframework.stereotype.Component") || annotationType.equals("javax.annotation.ManagedBean") || annotationType.equals("javax.inject.Named");return isStereotype && attributes != null && attributes.containsKey("value");}protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return this.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 Introspector.decapitalize(shortClassName);}
}

3、DefaultBeanNameGenerator 类

下面是源码,就一个方法实现。

public class DefaultBeanNameGenerator implements BeanNameGenerator {public DefaultBeanNameGenerator() {}//实现接口方法,为某个bean生成名字public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return BeanDefinitionReaderUtils.generateBeanName(definition, registry);}
}

接着追踪,看看BeanDefinitionReaderUtils 的 generateBeanName()方法

public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {return generateBeanName(beanDefinition, registry, false);
}
//此方法被上面方法调用
public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException {//获取bean的类名(全路径类名)String generatedBeanName = definition.getBeanClassName();//如果类名为空时if (generatedBeanName == null) {//bean的父bean名字不为空时if (definition.getParentName() != null) {//此bean的名字就为:父bean名+$childgeneratedBeanName = definition.getParentName() + "$child";} //bean的工厂bean名字不为空时else if (definition.getFactoryBeanName() != null) {//此bean的名字就为:生产它的工厂bean名+$createdgeneratedBeanName = definition.getFactoryBeanName() + "$created";}}//bean的名字为null、“”、“ ”时,抛出异常if (!StringUtils.hasText(generatedBeanName)) {throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither 'class' nor 'parent' nor 'factory-bean' - can't generate bean name");} //此处isInnerBean 为falseelse if (isInnerBean) {String id = generatedBeanName + "#" + ObjectUtils.getIdentityHexString(definition);return id;} else {//返回bean的名字return uniqueBeanName(generatedBeanName, registry);}
}

继续追踪,看看uniqueBeanName()方法:

这个方法的意思是:如果generateBeanName()方法生成的bean名字,已经被注册了(即已经存在了),那么就在名字后加上#和数字,比如hehe名字已经存在了,那么此时如果generateBeanName()方法生成的名字还是hehe,那么此时就在hehe后面加上#0(hehe#0),就是#后的数字递增,来区分,因为bean的名字必须唯一。

public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {String id = beanName;for(int counter = -1; counter == -1 || registry.containsBeanDefinition(id); id = beanName + "#" + counter) {++counter;}return id;
}

bean名字生成的流程总结:bean将自己的全路径类名作为自己的bean名字,如果没有类名,那就看是否有父bean,如果有,假设父bean名字为hehe,那么就用hehe$child作为此子bean的名字,如果没有父bean,那就看bean的工厂bean的名字,如果有,假设工厂bean名字为haha,那么bean的名字就是haha$created,如果没有工厂,那就报错“既没有自己的类名、也没有父bean类名、也没有工厂bean类名”。不管最终用的是哪一个的名字,对这个名字进行唯一性检查,如果名字重复了(已经有这个名字存在了),那就在名字后面+#+数字,这样,每个bean的名字就是唯一的了。

spring系列——BeanNameGenerator接口(bean名字生成器)相关推荐

  1. 深入理解Spring系列之六:bean初始化

    <深入理解Spring系列之四:BeanDefinition装载前奏曲>中提到,对于非延迟单例bean的初始化在finishBeanFactoryInitialization(beanFa ...

  2. 学好spring系列之Wiring Bean(装配Bean)

    在上两篇的博文中,分别对spring框架中的两个很重要的概念DI(Dependency Injection)和AOP(Aspect-Oriented programming)做了介绍,或许不那么完美, ...

  3. spring系列-注解驱动原理及源码-bean组件注册

    目录 一.环境初始化 1.环境准备 二.bean的手动注入 1.xml方式注入bean 2.使用@Configuration&@Bean方式注入bean 三.自动扫描注册组件及bean 1.使 ...

  4. Spring系列第20篇:@Conditional通过条件来控制bean的注册

    面试阿里p7被问到的问题(当时我只知道第一个): @Conditional是做什么的? @Conditional多个条件是什么逻辑关系? 条件判断在什么时候执行? ConfigurationCondi ...

  5. Spring系列之bean的使用

    转载自 https://www.cnblogs.com/xiaoxi/p/5850095.html 一.Bean的定义 <bean id="userDao" class=&q ...

  6. Spring系列(八):Spring生命周期中BeanPostProcessor接口用法介绍

    今天给大家介绍BeanPostProcessor接口用法,希望对大家能有所帮助! 1.BeanPostProcessor 概念介绍 BeanPostProcessor接口通常被称为Bean的后置处理器 ...

  7. 实战系列-IDEA中Spring MVC实现接口功能

    导语   现在由于Spring Boot的简约化开发,很多的人都忘记了SSM框架接口是如何搭建的,这里就记录一次本人在实际开发中使用的如何去搭建一个Spring MVC的接口项目,当然这个功能整合完成 ...

  8. Spring - BeanDefinitionRegistryPostProcessor 扩展接口 动态注册bean

    文章目录 Pre org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor 接口的继承关系 BeanD ...

  9. Spring系列教程四:Spring对Bean的管理细节

    2019独角兽企业重金招聘Python工程师标准>>> 一.Spring创建bean的三种方式 ①使用默认构造函数创建 在spring配置文件中使用bean标签,配以id和class ...

最新文章

  1. CUDA学习日志:常量内存和纹理内存
  2. Android Studio在线安装Android SDK注意事项
  3. ios模拟器装ipa包_uni-app 打包ios上架app store流程
  4. 关于权限的数据库设计
  5. 获取SQL-SERVER数据库insert into操作的主键返回值
  6. php 表别名,MySQL和PHP – 不是唯一的表/别名
  7. 调用外部 DLL 中的函数(显示调用)
  8. 亚马逊向GuardDuty服务添加三种新的威胁检测规则
  9. oracle分析函数技术详解(配上开窗函数over())
  10. 简单java数组程序_最简单易懂的java数组排序方法整理
  11. IB驱动包下载 : Ubuntu 16.04 的 IB驱动 iso、source包、tgz包
  12. 【五步完美整理Windows系统】
  13. ubuntu中非常好用的PDF软件—okular
  14. CATIA飞机协同设计制造图形工作站配置方案
  15. 苹果电脑怎么更换计算机模式,苹果电脑装windows7后怎么切回来_苹果电脑安装win7后如何切换...
  16. Mybatis丶Mybatis-Plus
  17. html5 图片处理 开源,AlloyImage 基于 HTML5 的专业级图像处理开源引擎 - 文章教程...
  18. python ipo模型是指什么
  19. 2023最火批量getshell工具
  20. Android开源库总结

热门文章

  1. 布袋除尘器过滤风速多少_布袋除尘器过滤风速的确定标准是什么?
  2. tinyint(1)和int(1)的区别
  3. 双目相机实现物体三维重建,得到三维点云
  4. Linux tty串口测试程序
  5. 多线程堆排序算法C语言实现
  6. matlab mstg函数,matlabfilter
  7. Huggingface Transformers库学习笔记(二):使用Transformers(上)(Using Transformers Part 1)
  8. Meterpreter渗透测试入门
  9. oracle 报12560,UNIX系统中Oracle报TNS-12560错误的解决思路
  10. OJDBC版本区别 [ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别]