我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指定其id和name值,但那些没有指定的,或者注解的spring的beanname怎么来的的?就是BeanNameGenerator接口实现的特性。

  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory" /></bean>

  BeanNameGenerator接口位于 org.springframework.beans.factory.support 包下面,只声明了一个方法,接受两个参数:definition 被生成名字的BeanDefinition实例;registry 生成名字后注册进的BeanDefinitionRegistry。

    /*** Generate a bean name for the given bean definition.* 根据给定的bean definition 生成一个bean的名字* @param definition the bean definition to generate a name for* @param 参数 definition 需要生成bean name的BeanDefinition实例* @param registry the bean definition registry that the given definition* is supposed to be registered with* @param 参数registry 是 definition 注册* @return the generated bean name* @return 返回生成的bean name*/String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);

  BeanNameGenerator有两个实现版本,DefaultBeanNameGenerator和AnnotationBeanNameGenerator。其中DefaultBeanNameGenerator是给资源文件加载bean时使用(BeanDefinitionReader中使用);AnnotationBeanNameGenerator是为了处理注解生成bean name的情况。

  DefaultBeanNameGenerator类将具体的处理方式委托给了,BeanDefinitionReaderUtils#generateBeanName(BeanDefinition, BeanDefinitionRegistry)方法处理。  

    /*** Generate a bean name for the given top-level bean definition,    * unique within the given bean factory.* @param beanDefinition the bean definition to generate a bean name for* @param registry the bean factory that the definition is going to be* registered with (to check for existing bean names)* @return the generated bean name* @throws BeanDefinitionStoreException if no unique name can be generated* for the given bean definition*/public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {return generateBeanName(beanDefinition, registry, false);}

  这个方法也没有做任何处理,直接委托了给了generateBeanName(BeanDefinition , BeanDefinitionRegistry , boolean )方法,多指定了一个boolean型参数,是为了区分内部bean(innerBean)和顶级bean(top-level bean).

/*** Generate a bean name for the given bean definition, unique within the* given bean factory.* @param definition the bean definition to generate a bean name for* @param registry the bean factory that the definition is going to be* registered with (to check for existing bean names)* @param isInnerBean whether the given bean definition will be registered* as inner bean or as top-level bean (allowing for special name generation* for inner beans versus top-level beans)    * @param isInnerBean  参数definition会被注册为一个内部bean还是一个顶级bean(内部bean和顶级bean 都允许使用特殊名字定义)* @return the generated bean name* @throws BeanDefinitionStoreException if no unique name can be generated* for the given bean definition* @throws BeanDefinitionStoreException 当没有唯一的名称可供生成的时候抛出异常*/public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)throws BeanDefinitionStoreException {//generatedBeanName定义为类前缀, 读取bean的className,不一定是运行时的实际类型。String generatedBeanName = definition.getBeanClassName();if (generatedBeanName == null) {//如果类名称为空,那读取bean的parent bean name if (definition.getParentName() != null) {generatedBeanName = definition.getParentName() + "$child";}//否则,读取生成该bean的factoryBean name名称做前缀。else if (definition.getFactoryBeanName() != null) {generatedBeanName = definition.getFactoryBeanName() + "$created";}}//generatedBeanName为空字符串,抛出异常if (!StringUtils.hasText(generatedBeanName)) {throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");}String id = generatedBeanName;//当为内部bean时,调用系统底层的object唯一标识码生成if (isInnerBean) {// Inner bean: generate identity hashcode suffix. id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);}//否则即为顶级bean,生成策略是前缀+循环数字,直到找到对应自增idelse {// Top-level bean: use plain class name.// Increase counter until the id is unique.int counter = -1;while (counter == -1 || registry.containsBeanDefinition(id)) {counter++;id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;}}return id;}

  关于每个对象的hash code的生成方式,这里面不确定是否和对象重写的hashCode()方法有关,需要jvm相关资料说明。

//    ObjectUtils.java/*** Return a hex String form of an object's identity hash code.* 返回一个十六进制数从hash code中获得* @param obj*            the object* @return the object's identity code in hex notation*/public static String getIdentityHexString(Object obj) {return Integer.toHexString(System.identityHashCode(obj));}//    System.java/*** Returns the same hash code for the given object as would be returned by* the default method hashCode(), whether or not the given object's class* overrides hashCode(). The hash code for the null reference is zero.* * @param x*            object for which the hashCode is to be calculated* @return the hashCode* @since JDK1.1*///native 表示操作系统实现的底层框架,用于生成对象的hashcode。jvm的实现还没有关心。public static native int identityHashCode(Object x);//  Integer.java/*** All possible chars for representing a number as a String*/final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l','m', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y','z' };public static String toHexString(int i) {return toUnsignedString(i, 4);}private static String toUnsignedString(int i, int shift) {char[] buf = new char[32];int charPos = 32;int radix = 1 << shift;int mask = radix - 1;do {buf[--charPos] = digits[i & mask];i >>>= shift;} while (i != 0);return new String(buf, charPos, (32 - charPos));}

  重新整理下流程:生成流程分为前后两部分,前面生成的叫前缀,后面生成的叫后缀。

    1,读取待生成name实例的类名称,未必是运行时的实际类型。

    2,如果类型为空,则判断是否存在parent bean,如果存在,读取parent bean的name+"$child"。

    3,如果parent bean 为空,那么判断是否存在factory bean ,如存在,factory bean name + "$created".前缀生成完毕。

    4,如果前缀为空,直接抛出异常,没有可以定义这个bean的任何依据。

    5,前缀存在,判断是否为内部bean(innerBean,此处默认为false),如果是,最终为前缀+分隔符+十六进制的hashcode码、

    6,如果是顶级bean(top-level bean ),则判断前缀+数字的bean是否已存在,循环查询,知道查询到没有使用的id为止。处理完成。

  DefaultBeanNameGenerator处理的问题就这些了。

      

转载于:https://www.cnblogs.com/jason0529/p/5272265.html

Spring源码入门——DefaultBeanNameGenerator解析相关推荐

  1. Spring源码入门——AnnotationBeanNameGenerator解析

    ---恢复内容开始--- 接上篇,上篇解析了DefaultBeanGenerator生成bean name的过程(http://www.cnblogs.com/jason0529/p/5272265. ...

  2. Spring源码-applicationcontext.xml解析过程

    为什么80%的码农都做不了架构师?>>>    Spring源码-applicationcontext.xml解析过程 核心流程:Spring中对于applicationcontex ...

  3. Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(三)-Controller 解析

    在之前的博客中Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(一),己经对 Spring MVC 的框架做了详细的分析,但是有一个问题,发现举的例子不常用,因为我们在实际开发项 ...

  4. Spring源码深度解析(郝佳)-学习-ASM 类字节码解析

    我们在Java字节码文件结构剖析(二)中己经对MyTest35_1这个类的字节码做了完整的解析,今天,我们来看看Spring的ASM技术是如何来解析Java类字节码的.话不多说,先上实例. MyTes ...

  5. Spring源码——XmlBeanFactory流程

    前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...

  6. spring 源码分析(1)-xml文件解析

    我们在最开始接触spring的时候,看到不少书spring入门的例子如下 ApplicationContext atx = new ClassPathXmlApplicationContext(&qu ...

  7. Spring 源码解读第七弹!bean 标签的解析

    Spring 源码解读继续. 本文是 Spring 系列第八篇,如果小伙伴们还没阅读过本系列前面的文章,建议先看看,这有助于更好的理解本文. Spring 源码解读计划 Spring 源码第一篇开整! ...

  8. spring源码分析01-(前期准备)spring核心原理解析和手写简易spring

    1.本文主要介绍内容 本文会把Spring中核心知识点大概解释下.可以对Spring的底层有一个整体的大致了解.主要内容包括: 手写简易spring框架,帮助更好理解spring. 代码点击链接自取 ...

  9. Spring源码学习(一)--Spring底层核心原理解析

    目录 Spring中是如何创建一个对象? Bean的创建过程 推断构造方法 AOP大致流程 Spring事务 最近在跟视频学习spring源码,将每节课记录下来,以后好来复习. 首先把Spring中核 ...

最新文章

  1. 网上整理的对于Rest和Restful api的理解
  2. 使用FIO对SATA、SSD和PCIe Flash进行测试
  3. python语言怎么用-学习如何使用 Python 程式语言
  4. python在哪里学比较好-Python哪里学习好?老男孩python入门
  5. hadoop2.8 ha 集群搭建
  6. 有关Spring注解@xxx的零碎知识
  7. route map应用策略路由(下)
  8. oracle修改数据库国际字符集,Oracle修改数据库字符集
  9. linux服务器查配置信息失败,查看Linux服务器的配置信息
  10. vue 搜索框header_vue项目header模块编写
  11. (转) OpenLayers3基础教程——加载资源
  12. 高考分数出来了,计算机专业选择那个方向更香?
  13. 毕业设计论文封面模板
  14. Linux文件系统的正确挂载方式
  15. winform给textBox控件设置默认值
  16. android手机壁纸尺寸,安卓手机壁纸尺寸选择攻略:屏幕分辨率≠壁纸分辨率
  17. MongoDB从入门到高级的实战操作
  18. 37.大数据之旅——网站流量统计项目
  19. Elasticsearch摄取节点(八)——数据解析处理器
  20. 程序员进 ICU 昏迷五六天,恢复后决定辞职回乡改行送菜

热门文章

  1. 实现option上下移动_ES6原生实战Uploader工具类(从设计到实现)
  2. PDA连接远程SQL 2005数据库
  3. Kafka 分区备份实战
  4. tomcat之一:指定tomcat运行时JDK版本
  5. iOS开发值多线程简单介绍
  6. 关于APP性能测试脚本录制的四种方法
  7. Java ---学习笔记(泛型)
  8. [zz]shell 中条件测试
  9. 在职工象棋赛上弃子拿下一盘
  10. 个人总结:网站优化之title、meta、keywords写法