Spring源码入门——DefaultBeanNameGenerator解析

时间:2022-09-27 21:44:48

  我们知道在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,生成策略是前缀+循环数字,直到找到对应自增id
else {
// 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处理的问题就这些了。

      

Spring源码入门——DefaultBeanNameGenerator解析的更多相关文章

  1. Spring源码入门——DefaultBeanNameGenerator解析 转发 https&colon;&sol;&sol;www&period;cnblogs&period;com&sol;jason0529&sol;p&sol;5272265&period;html

    Spring源码入门——DefaultBeanNameGenerator解析   我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...

  2. Spring源码入门——XmlBeanDefinitionReader解析

    接上篇[] ,我们看到BeanDefinitionReader解决的是从资源文件(xml,propert)到BeanDefinition集合的过程.所以BeanDefinitionReader接口有两 ...

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

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

  4. 从零开始学spring源码之xml解析&lpar;一&rpar;:入门

    谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了jav ...

  5. 从零开始学spring源码之xml解析&lpar;二&rpar;:默认标签和自定义标签解析

    默认标签: 上一篇说到spring的默认标签和自定义标签,发现这里面东西还蛮多的.决定还是拆开来写.今天就来好好聊聊这两块是怎么玩的,首先我们先看看默认标签: private void parseDe ...

  6. spring 源码解析

    1. [文件] spring源码.txt ~ 15B     下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB     下载( ...

  7. Spring源码深度解析

    Spring源码分析 Spring Web入门及源码学习 [Spring源码分析]Bean加载流程概览 Spring Framework 实现原理与源码解析系统 Spring源码分析--水门 Spri ...

  8. Spring源码解析02:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  9. Spring源码解析 &vert; 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

随机推荐

  1. 剑指Offer面试题:19&period;包含Min函数的栈

    一.题目:包含Min函数的栈 题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数.在该栈中,调用min.push及pop的时间复杂度都是O(1). 这里我们要实现的就是min ...

  2. python获取命令行参数的方法

    想用python处理一下文件,发现有argv这个用法,搜来学习一下. 如果想对python脚步传参数,那么就需要命令行参数的支持了,这样可以省的每次去改脚步了. 用法是:python    xx.py ...

  3. CSS的叠加

    CSS中的叠加分为以下三种: 1.上下叠加 CSS部分: #div1{ width:200px; height:50px; margin-bottom:30px; background:#ffff00 ...

  4. struts2中访问servlet API

    Struts2中的Action没有与任何Servlet API耦合,,但对于WEB应用的控制器而言,不访问Servlet API几乎是不可能的,例如需要跟踪HTTP Session状态等.Struts ...

  5. &lbrack;Angular Tutorial&rsqb; 10 -More Templating

    在这一步中,我们会实现电话细节的视图,这在用户点击列表中的一部电话时被展示. ·当您点击列表中的一部电话时,带有电话特定信息的电话细节页面将被展示. 我们打算使用$http来获取我们的数据,以此来实现 ...

  6. 【Netty】Netty之ByteBuf

    一.前言 前面已经学习了Netty中传输部分,现在接着学习Netty中的ByteBuf. 二.ByteBuf 2.1 ByteBuf API 在网络上传输的数据形式为Byte,Java NIO提供了B ...

  7. PDF如何去除背景,PDF去除背景颜色

    PDF文件在使用的时候大多都是单调的白色背景,但是也有小伙伴再制作PDF文件的时候会给PDF文件添加背景颜色,会有影响文字阅读的情况,这个时候就需要把背景颜色去除了,那么该怎么做呢,不会的小伙们就跟小 ...

  8. Luogu1514 NOIP2010 引水入城 BFS、贪心

    传送门 NOIP的题目都难以写精简题意 考虑最上面一排的某一个点对最下面一排的影响是什么样的,不难发现必须要是一段连续区间才能够符合题意. 如果不是一段连续区间,意味着中间某一段没有被覆盖的部分比周围 ...

  9. 每天进步一点点——论fork&lpar;&rpar;函数与Linux中的多线程编程

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/27316803 一.fork()函数     在操作系统的基本概念中进程是程序的一次运行,且是 ...

  10. 【Java】对象的创建过程

    一.对象的创建过程 1.首次创建对象时或该类静态方法/静态域首次被访问时,JAVA解释器查找该类的路径,定位该类的class文件 2.载入该类的class文件,有关静态初始化的所有动作执行,但是只执行 ...