Spring源码入门——DefaultBeanNameGenerator解析

  我们知道在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处理的问题就这些了。

来源: http://www.cnblogs.com/jason0529/p/5272265.html

来自为知笔记(Wiz)

时间: 2024-10-19 07:09:09

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

Spring源码入门——XmlBeanDefinitionReader解析

接上篇[] ,我们看到BeanDefinitionReader解决的是从资源文件(xml,propert)到BeanDefinition集合的过程.所以BeanDefinitionReader接口有两个实现版本. BeanDefinitionReader的接口声明,ResourceLoader是spring中解决Resource加载的操作.四个loadBeanDefinitions就是重载解决单个或者多个资源文件的处理问题. loadBeanDefinitions 是加载BeanDefiniti

Spring源码入门——AnnotationBeanNameGenerator解析

---恢复内容开始--- 接上篇,上篇解析了DefaultBeanGenerator生成bean name的过程(http://www.cnblogs.com/jason0529/p/5272265.html ), 本篇我们继续解析另一类bean name生成方式. spring定义bean有两种模式,配置文件(xml,properties)和注解.注:jpa的声明接口生成bean应该可以算第三种模式,这里不讨论. 对两种bean定义方式,spring提供了两种不同的bean name实现方式去

Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二) 前言 看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了 解决上篇文章遗留的问题 getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping ge

spring源码剖析(二)Spring默认标签解析及注册实现

在使用spring的时候,我也经常会使用到bean标签,beans标签,import标签,aop标签等. 下面主要为读者介绍spring的默认的自带标签的解析流程. 验证模式(DTD&XSD) dtd基本已被淘汰,现在spring的验证模式基本都是采用xsd文件作为xml文档的验证模式,通过xsd文件可以检查该xml是否符合规范,是否有效.在使用xsd文件对xml文档进行校验的时候,除了要名称空间外(xmlns="http://www.springframework.org/schema

spring源码(3)之解析配置文件的过程

spring源码之解析配置文件过程 上篇博文,我们探讨了spring获取配置文件applicationContext.xml的document对象.回想struct2解析struct*.xml,当struct2获取struct*.xml文件的document对象之后,就会循环遍历这个document,然把不同的标签的信息封装到不同的对象中,如<package>标签封装到packageConfig对象,<action>标签封装到actionConfig对象等等.那么spring在获取

Spring源码深度解析第一天

其实第一天已经过去了,今天是第二天.iteye刚注册的小号就被封了.不论是它的失误还是他的失误总之我跟iteye是没有缘分了. 昨天基本没有进展.所以从今天开始说了.下面流水账开始了. <Spring源码深度解析>这本书没有pdf完整版是让我很失望的.如果有完整版即使看完了我也会选择买一本实体如果有用的话. 书中说从github下载源码.发现github没有想象中的简单易懂.还需要记忆很多命令才能玩得转.从github上获得了Spring源码后需要使用Gradle来编译成eclipse项目.g

SPRING技术内幕,Spring源码深度解析

 SPRING技术内幕,Spring源码深度解析 SPRING技术内幕:深入解析SPRING架构与设计原理(第2版)[带书签].pdf: http://www.t00y.com/file/78131650 Spring源码深度解析 [郝佳编著] sample.pdf: http://www.t00y.com/file/78131634 [jingshuishenliu.400gb.com]Spring Data.pdf: http://www.t00y.com/file/78256084 [

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

软件开发工程师(JAVA)中级考试大纲--spring源码解析

spring源码解析(1)----IOC 一.IOC容器 在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,不同的形式的定义信息来建立我们需要的IoC容器. 在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定