博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码入门——DefaultBeanNameGenerator解析
阅读量:4338 次
发布时间:2019-06-07

本文共 6793 字,大约阅读时间需要 22 分钟。

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

  

  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/jeffen/p/6394770.html

你可能感兴趣的文章
crontab导致磁盘空间满问题的解决
查看>>
java基础 第十一章(多态、抽象类、接口、包装类、String)
查看>>
Hadoop 服务器配置的副本数量 管不了客户端
查看>>
欧建新之死
查看>>
自定义滚动条
查看>>
APP开发手记01(app与web的困惑)
查看>>
笛卡尔遗传规划Cartesian Genetic Programming (CGP)简单理解(1)
查看>>
mysql 日期时间运算函数(转)
查看>>
初识前端作业1
查看>>
ffmpeg格式转换命令
查看>>
万方数据知识平台 TFHpple +Xpath解析
查看>>
Hive实现oracle的Minus函数
查看>>
秒杀多线程第四篇 一个经典的多线程同步问题
查看>>
RocketMQ配置
查看>>
蚂蚁金服井贤栋:用技术联手金融机构,形成服务小微的生态合力
查看>>
端口号大全
查看>>
机器学习基石笔记2——在何时可以使用机器学习(2)
查看>>
POJ 3740 Easy Finding (DLX模板)
查看>>
MySQL 处理重复数据
查看>>
关于typedef的用法总结(转)
查看>>