亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring BeanName 的自動(dòng)生成原理示例詳解

 更新時(shí)間:2023年09月18日 09:55:41   作者:泠青沼~  
這篇文章主要介紹了Spring BeanName 的自動(dòng)生成原理示例詳解,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

?? 一、默認(rèn) name 生成原理

在 Spring 中,提供了 BeanNameGenerator 用來(lái)生成 BeanName:

public interface BeanNameGenerator {
	/**
	 * Generate a bean name for the given bean definition.
	 * @param definition the bean definition to generate a name for
	 * @param registry the bean definition registry that the given definition
	 * is supposed to be registered with
	 * @return the generated bean name
	 */
	String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}

在這里插入圖片描述

  • DefaultBeanNameGenerator:XML 配置中,默認(rèn)的 BeanName 就是在這個(gè)中自動(dòng)生成的
  • AnnotationBeanNameGenerator:Java 配置中,如果使用了 @Component 等注解標(biāo)記的 Bean,沒(méi)有設(shè)置默認(rèn)的名稱(chēng),則通過(guò)這個(gè)來(lái)生成默認(rèn)的 BeanName
public class DefaultBeanNameGenerator implements BeanNameGenerator {
	/**
	 * A convenient constant for a default {@code DefaultBeanNameGenerator} instance,
	 * as used for {@link AbstractBeanDefinitionReader} setup.
	 * @since 5.2
	 */
	public static final DefaultBeanNameGenerator INSTANCE = new DefaultBeanNameGenerator();
	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
	}
}

可以看到,generateBeanName 這個(gè)方法實(shí)際上代理了 BeanDefinitionReaderUtils.generateBeanName 方法的執(zhí)行,真正的 BeanName 的生成是在這個(gè)方法中完成的

在這里插入圖片描述

public static String generateBeanName(
		BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
		throws BeanDefinitionStoreException {
    // 這里就是獲取到 XML 中 bean 標(biāo)簽里邊配置的 class 屬性的值
	String generatedBeanName = definition.getBeanClassName();
    // 判斷是否有 class 這個(gè)屬性值,如果沒(méi)有的話,則在 parnetName 存在的情況下,
    // 使用 parentName+$child 來(lái)作為 生成的 beanName
	if (generatedBeanName == null) {
		if (definition.getParentName() != null) {
			generatedBeanName = definition.getParentName() + "$child";
		}
        // 如果沒(méi)有 parentName,則嘗試使用 factoryBeanName
		else if (definition.getFactoryBeanName() != null) {
			generatedBeanName = definition.getFactoryBeanName() + "$created";
		}
	}
    // 如果經(jīng)過(guò)上面的處理,還是沒(méi)有 generatedBeanName,那么就要拋異常了
	if (!StringUtils.hasText(generatedBeanName)) {
		throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
				"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
	}
	if (isInnerBean) {
		// Inner bean: generate identity hashcode suffix.
		return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
	}
	// Top-level bean: use plain class name with unique suffix if necessary.
    // 我們的默認(rèn) BeanName,實(shí)際上是在這個(gè)方法中生成的
	return uniqueBeanName(generatedBeanName, registry);
}
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
	String id = beanName;
	int counter = -1;
	// Increase counter until the id is unique.
    //GENERATED_BEAN_NAME_SEPARATOR 實(shí)際上就是 #
    // 所有這里是把類(lèi)的全路徑和 # 拼在一起
	String prefix = beanName + GENERATED_BEAN_NAME_SEPARATOR;
    // 后面的判斷表示這個(gè) id 是否已經(jīng)被注冊(cè)了,如果已經(jīng)被注冊(cè),則繼續(xù)生成新的 id
	while (counter == -1 || registry.containsBeanDefinition(id)) {
		counter++;
		id = prefix + counter;
	}
    //最終生成的 id 就是 org.javaboy.bean.User#0
	return id;
}

由此可以看到,默認(rèn)的 BeanName 就是類(lèi)的全路徑+ # +序列號(hào),如 com.dong.Cat#0 、 com.dong.Cat#1 。對(duì)于序列號(hào)為 0 的 BeanName,還有一個(gè)默認(rèn)的名稱(chēng),就是類(lèi)的全路徑,不加任何序列號(hào)上面這個(gè)生成 BeanName 的方法是在 BeanDefinitionParserDelegate#parseBeanDefinitionElement 方法中執(zhí)行的,具體的邏輯如下:

if (beanDefinition != null) {
    // 當(dāng)前沒(méi)有配置 BeanName,即 bean 標(biāo)簽中沒(méi)有 id 或者 name 屬性
	if (!StringUtils.hasText(beanName)) {
		try {
			if (containingBean != null) {
				beanName = BeanDefinitionReaderUtils.generateBeanName(
						beanDefinition, this.readerContext.getRegistry(), true);
			}
			else {
                //這個(gè)地方,最終會(huì)調(diào)用到上面的邏輯去生成 BeanName
                //com.dong.Cat#0
				beanName = this.readerContext.generateBeanName(beanDefinition);
				// Register an alias for the plain bean class name, if still possible,
				// if the generator returned the class name plus a suffix.
				// This is expected for Spring 1.2/2.0 backwards compatibility.
                // 獲取一個(gè)類(lèi)的全路徑 com.dong.Cat
                //!this.readerContext.getRegistry().isBeanNameInUse(beanClassName) 表示 beanClassName 還沒(méi)有作為一個(gè) BeanName 注冊(cè)到 Spring 容器中
				String beanClassName = beanDefinition.getBeanClassName();
				if (beanClassName != null &&
						beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
						!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
					//將之添加別名中,相當(dāng)于類(lèi)的全路徑本身,成為了 Bean 的一個(gè)別名
                    aliases.add(beanClassName);
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Neither XML 'id' nor 'name' specified - " +
						"using generated bean name [" + beanName + "]");
			}
		}
		catch (Exception ex) {
			error(ex.getMessage(), ele);
			return null;
		}
	}
	String[] aliasesArray = StringUtils.toStringArray(aliases);
	return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

這就是為什么默認(rèn)生成的 BeanName 中,#0可有可無(wú)的原因

?? 二、id 和 name 屬性處理原理

id 和 name 屬性的處理其實(shí)也是在 BeanDefinitionParserDelegate#parseBeanDefinitionElement 方法中:

// 獲取 bean 標(biāo)簽中的 id 屬性值,user
String id = ele.getAttribute(ID_ATTRIBUTE);
// 獲取 bean 標(biāo)簽中 name 屬性值,user;user2;user3
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
    //MULTI_VALUE_ATTRIBUTE_DELIMITERS 變量實(shí)際上就是 ;,空格
    // 所以這個(gè)方法實(shí)際上就是根據(jù) ; , 以及 空格 去拆分 nameAttr,將之拆分為一個(gè)數(shù)組
	String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
	// name 拆出來(lái)的屬性將作為這個(gè) bean 的別名
    aliases.addAll(Arrays.asList(nameArr));
}
//使用 id 作為 beanName
String beanName = id;
//這里相當(dāng)于判斷這個(gè) bean 標(biāo)簽沒(méi)有 id 屬性,但是有 name 屬性
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    //將 name 拆出來(lái)的集合中的第一項(xiàng)作為 beanName
	beanName = aliases.remove(0);
	if (logger.isTraceEnabled()) {
		logger.trace("No XML 'id' specified - using '" + beanName +
				"' as bean name and " + aliases + " as aliases");
	}
}

但是,經(jīng)過(guò)上面的處理,beanName 還是有可能為空。如果還為空,則進(jìn)入到上面的邏輯中,自動(dòng)生成 BeanName

到此這篇關(guān)于Spring BeanName 的自動(dòng)生成原理的文章就介紹到這了,更多相關(guān)Spring BeanName自動(dòng)生成原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法

    超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法

    這篇文章主要介紹了超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 解決Java中SimpleDateFormat線程不安全的五種方案

    解決Java中SimpleDateFormat線程不安全的五種方案

    SimpleDateFormat 就是一個(gè)典型的線程不安全事例,本文主要介紹了解決Java中SimpleDateFormat線程不安全的五種方案,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • java向上轉(zhuǎn)型與向下轉(zhuǎn)型詳解

    java向上轉(zhuǎn)型與向下轉(zhuǎn)型詳解

    這篇文章主要為大家詳細(xì)介紹了java向上轉(zhuǎn)型與向下轉(zhuǎn)型,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Java?Maven構(gòu)建工具中mvnd和Gradle誰(shuí)更快

    Java?Maven構(gòu)建工具中mvnd和Gradle誰(shuí)更快

    這篇文章主要介紹了Java?Maven構(gòu)建工具中mvnd和Gradle誰(shuí)更快,mvnd?是?Maven?Daemon?的縮寫(xiě)?,翻譯成中文就是?Maven?守護(hù)進(jìn)程,下文更多相關(guān)資料,需要的小伙伴可以參考一下
    2022-05-05
  • SpringMVC視圖作用詳解

    SpringMVC視圖作用詳解

    這篇文章主要介紹了springMVC中的視圖與視圖解析器,springMVC視圖的種類(lèi)很多,默認(rèn)有轉(zhuǎn)發(fā)視圖和重定向視圖,本文就每一種視圖給大家詳細(xì)介紹,需要的朋友可以參考下
    2022-11-11
  • Java實(shí)現(xiàn)發(fā)紅包功能

    Java實(shí)現(xiàn)發(fā)紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)發(fā)紅包功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • JAVA中的OutputStreamWriter流解析

    JAVA中的OutputStreamWriter流解析

    這篇文章主要介紹了JAVA中的OutputStreamWriter流解析,OutputStreamWriter提供了一種方便的方式將字符數(shù)據(jù)寫(xiě)入到輸出流中,并進(jìn)行字符編碼轉(zhuǎn)換,它是Java中處理字符流和字節(jié)流之間轉(zhuǎn)換的重要工具之一,需要的朋友可以參考下
    2023-10-10
  • JVM 命令行工具的使用

    JVM 命令行工具的使用

    造成Java應(yīng)用出現(xiàn)性能問(wèn)題的因素非常多,想要定位這些問(wèn)題,一款優(yōu)秀的性能診斷工具必不可少,本文主要介紹了JVM 命令行工具的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-04-04
  • Java 常見(jiàn)的限流算法詳細(xì)分析并實(shí)現(xiàn)

    Java 常見(jiàn)的限流算法詳細(xì)分析并實(shí)現(xiàn)

    大數(shù)據(jù)量高并發(fā)訪問(wèn)時(shí),經(jīng)常出現(xiàn)服務(wù)或接口面對(duì)暴漲的請(qǐng)求而不可用的情況,甚至引發(fā)連鎖反映導(dǎo)致整個(gè)系統(tǒng)崩潰。此時(shí)你需要使用的技術(shù)手段之一就是限流,當(dāng)請(qǐng)求達(dá)到一定的并發(fā)數(shù)或速率,就進(jìn)行等待、排隊(duì)、降級(jí)、拒絕服務(wù)等。限流時(shí),常見(jiàn)算法是計(jì)數(shù)器、漏斗、令牌桶算法
    2022-04-04
  • Java并發(fā)編程ArrayBlockingQueue的使用

    Java并發(fā)編程ArrayBlockingQueue的使用

    ArrayBlockingQueue是一個(gè)備受矚目的有界阻塞隊(duì)列,本文將全面深入地介紹ArrayBlockingQueue的內(nèi)部機(jī)制、使用場(chǎng)景以及最佳實(shí)踐,感興趣的可以了解一下
    2024-08-08

最新評(píng)論