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,生成策略是前綴+循環數字,直到找到對應自增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處理的問題就這些了。

       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM