我們知道在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處理的問題就這些了。
