欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文帶你了解Spring中Bean名稱加載機制

 更新時間:2024年01月14日 09:13:00   作者:FirstMrRight  
這篇文章主要給大家介紹了Spring Framework如何從使用注解定義的Bean元數(shù)據(jù)中獲取到Bean的名稱,文中通過代碼示例給大家介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下

前言

通過前文:《深入分析-Spring BeanDefinition構(gòu)造元信息》一文我們可以了解到:Spring Framework共有三種方式可以定義Bean,分別為:XML配置文件、注解、Java配置類, 從Spring Framework 3.0(2019年12月發(fā)布)版本開始推薦使用注解來定義Bean,而不是XML配置文件,因此,本文的重點是放在探索Spring Framework如何從使用注解定義的Bean元數(shù)據(jù)中獲取到Bean的名稱。

AnnotationBeanNameGenerator類的介紹

作用

AnnotationBeanNameGenerator在Spring Framework中用于生成基于注解的Bean名稱,其主要作用是根據(jù)指定的注解信息,生成符合規(guī)范的Bean名稱。它在Spring容器初始化時,通過掃描注解配置的組件類,并且根據(jù)其定義的命名規(guī)則生成Bean名稱,然后將這些名稱與對應的Bean實例關(guān)聯(lián)起來。

如:你在工程中使用@Service注解定義了一個HelloService的Bean,那么你在啟動SpringBoot工程后,該Bean會以beanName為“helloService”注入到Spring容器中。

/**
 * @author 公眾號:種棵代碼技術(shù)樹
 */
@Service
public class HelloService {

    private final Logger logger = LoggerFactory.getLogger(HelloService.class);

    private final HelloAsyncService helloAsyncService;

    /**
     * Instantiates a new Hello service.
     *
     * @param helloAsyncService the hello async service
     */
    public HelloService(HelloAsyncService helloAsyncService) {
        this.helloAsyncService = helloAsyncService;
    }
}

計算代碼中用于返回Bean名稱的StringUtils.uncapitalizeAsProperty(shortClassName);即可得到:

同時還可以看到上一篇文章:《深入分析-Spring BeanDefinition構(gòu)造元信息》中有關(guān)BeanDefinition的內(nèi)容,如:Bean的全限定類名和作用域。

繼承關(guān)系

AnnotationBeanNameGeneratorBeanNameGenerator接口的實現(xiàn)類,該接口的主要功能是為給定的Bean生成唯一的名稱。目前,BeanNameGenerator接口有兩個實現(xiàn),除了本篇文章介紹的AnnotationBeanNameGenerator外,還有默認實現(xiàn)類DefaultBeanNameGeneratorDefaultBeanNameGenerator主要用于處理通過XML文件定義的Bean,為其自動生成名稱。FullyQualifiedAnnotationBeanNameGenerator繼承自AnnotationBeanNameGenerator,同樣屬于BeanNameGenerator接口的實現(xiàn)類,該類覆寫了AnnotationBeanNameGeneratorbuildDefaultBeanName()方法,作用是使用注解類型和注解元數(shù)據(jù),結(jié)合其他信息(例如類名、包名等),生成帶有完全限定名的Bean名稱。

源碼結(jié)構(gòu)

  • 類聲明部分:定義了AnnotationBeanNameGenerator類,并實現(xiàn)了BeanNameGenerator接口。
  • 日志處理部分:定義了一個靜態(tài)的Log對象logger,用于記錄日志信息。
  • Bean名稱生成方法:實現(xiàn)了generateBeanName()方法,用于根據(jù)給定的Bean定義生成Bean名稱。如果Bean定義是一個帶注解的Bean定義,會調(diào)用determineBeanNameFromAnnotation()方法來基于注解生成Bean名稱;否則會使用默認的Bean名稱生成策略buildDefaultBeanName()方法來生成Bean名稱。
  • 注解處理部分:定義了determineBeanNameFromAnnotation()方法和isStereotypeWithNameValue()方法,用于判斷是否需要處理注解元數(shù)據(jù),從中獲取Bean名稱。
  • 默認Bean名稱生成策略部分:實現(xiàn)了buildDefaultBeanName()方法和getComponentAnnotation()方法,用于生成默認的Bean名稱。
  • 其他輔助方法:例如isStereotypeWithNameValue()方法和getComponentAnnotation()方法,用于支持上述方法的實現(xiàn)。

當@value配置值時:

@Service(value = "HelloService")

實現(xiàn)原理

@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    if (definition instanceof AnnotatedBeanDefinition) {
        String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
        if (StringUtils.hasText(beanName)) {
            // Explicit bean name found.
            return beanName;
        }
    }
    // Fallback: generate a unique default bean name.
    return buildDefaultBeanName(definition, registry);
}

如果當前BeanDefinitionAnnotationBeanNameGenerator類型,則嘗試從注解中獲取Bean的名稱,如果找了BeanName,則直接返回。

	/**
	 * Derive a bean name from one of the annotations on the class.
	 * @param annotatedDef the annotation-aware bean definition
	 * @return the bean name, or {@code null} if none is found
	 */
	@Nullable
	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
		AnnotationMetadata amd = annotatedDef.getMetadata();
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
			if (attributes != null) {
				Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
					Set<String> result = amd.getMetaAnnotationTypes(key);
					return (result.isEmpty() ? Collections.emptySet() : result);
				});
				if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
					Object value = attributes.get("value");
					if (value instanceof String) {
						String strVal = (String) value;
						if (StringUtils.hasLength(strVal)) {
							if (beanName != null && !strVal.equals(beanName)) {
								throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
										"component names: '" + beanName + "' versus '" + strVal + "'");
							}
							beanName = strVal;
						}
					}
				}
			}
		}
		return beanName;
	}

從某個注解中獲取Bean名稱,該方法是主要的BeanName獲取邏輯,其大體邏輯為:

  • 從Bean的元注解獲取數(shù)據(jù),遍歷源數(shù)據(jù)中的數(shù)據(jù)。
  • 獲取元數(shù)據(jù)的類型,如果元數(shù)據(jù)已被注入到容器池中,則直接返回結(jié)果。
  • 如果注解是否允許通過@Value注解來獲取bean名稱,如果可以通過@Value注解獲取Bean名稱,則使用元數(shù)據(jù)中@Value定義的信息為Bean名稱,最后返回,放入如果元數(shù)據(jù)中未配置@Value相關(guān)數(shù)據(jù),則返回null。
  • 當然,@Value中是可以不配置信息的,此時執(zhí)行fallBack,即調(diào)用 buildDefaultBeanName 方法生成一個默認的 Bean 名稱,并返回。
	/**
	 * Derive a default bean name from the given bean definition.
	 * <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}.
	 * @param definition the bean definition to build a bean name for
	 * @param registry the registry that the given bean definition is being registered with
	 * @return the default bean name (never {@code null})
	 */
	protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return buildDefaultBeanName(definition);
	}


	/**
	 * Derive a default bean name from the given bean definition.
	 * <p>The default implementation simply builds a decapitalized version
	 * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
	 * <p>Note that inner classes will thus have names of the form
	 * "outerClassName.InnerClassName", which because of the period in the
	 * name may be an issue if you are autowiring by name.
	 * @param definition the bean definition to build a bean name for
	 * @return the default bean name (never {@code null})
	 */
	protected String buildDefaultBeanName(BeanDefinition definition) {
		String beanClassName = definition.getBeanClassName();
		Assert.state(beanClassName != null, "No bean class name set");
		String shortClassName = ClassUtils.getShortName(beanClassName);
		return Introspector.decapitalize(shortClassName);
	}

該方法的作用是:從給定的 Bean 定義派生缺省 Bean 名稱。

默認實現(xiàn)只是構(gòu)建短類名的去大寫版本:例如“mypackage.MyJdbcDao“ -> ”myJdbcDao”。

經(jīng)過以上代碼,每個Bean均會獲得其對應的BeanName。

總結(jié)

AnnotationBeanNameGenerator 的優(yōu)點有:

  • 自動生成唯一的 Bean 名稱,避免了手動命名時出現(xiàn)重名的情況;
  • 提高了代碼可讀性和可維護性,因為通過注解來指定 Bean 名稱可以更直觀地表達 Bean 的含義;
  • 靈活性較高,支持多種類型的注解,例如 @Service、@Component、@Repository 等。

AnnotationBeanNameGenerator 的缺點則是:

  • 如果注解中未指定 Bean 名稱,該生成器會默認使用類名作為 Bean 名稱,這可能導致出現(xiàn)多個類名相同的 Bean,需要特別注意;
  • 由于生成的 Bean 名稱是自動生成的,因此有時可能不太符合開發(fā)者的命名習慣,需要手動修改 Bean 的名稱。

AnnotationBeanNameGenerator 在實際開發(fā)中可以幫助開發(fā)者快速生成唯一的 Bean 名稱,提高代碼的可讀性和可維護性,但需要特別注意類名重復以及自動生成的名稱是否符合需求。

最后

以上就是一文帶你了解Spring中Bean名稱加載機制的詳細內(nèi)容,更多關(guān)于Spring Bean名稱加載機制的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java創(chuàng)建對象之顯示創(chuàng)建與隱式創(chuàng)建

    Java創(chuàng)建對象之顯示創(chuàng)建與隱式創(chuàng)建

    在本篇文章中,小編會帶大家學習面向?qū)ο笾嘘P(guān)于對象的創(chuàng)建之顯示創(chuàng)建和隱式創(chuàng)建,其實類和對象作為面向?qū)ο笾凶罨镜?,也是最重要?需要的朋友可以參考下
    2023-05-05
  • SpringBoot實現(xiàn)掃碼登錄的示例代碼

    SpringBoot實現(xiàn)掃碼登錄的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)掃碼登錄的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 透徹理解Java中Synchronized(對象鎖)和Static Synchronized(類鎖)的區(qū)別

    透徹理解Java中Synchronized(對象鎖)和Static Synchronized(類鎖)的區(qū)別

    這篇文章主要介紹了Java中Synchronized(對象鎖)和Static Synchronized(類鎖)的區(qū)別,希望對大家有所幫助,一起跟隨小編過來看看吧
    2018-05-05
  • SpringMVC之AbstractAnnotationConfigDispatcherSer解讀

    SpringMVC之AbstractAnnotationConfigDispatcherSer解讀

    這篇文章主要介紹了SpringMVC之AbstractAnnotationConfigDispatcherSer,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • jvm垃圾回收之GC調(diào)優(yōu)工具分析詳解

    jvm垃圾回收之GC調(diào)優(yōu)工具分析詳解

    這篇文章主要為大家介紹了jvm垃圾回收之GC調(diào)優(yōu)工具的分析詳解,在進行JVM?GC性能調(diào)優(yōu)之前,需要使用某些工具獲取到當前應用的狀態(tài)信息
    2022-01-01
  • Java catch與throw同時使用的操作

    Java catch與throw同時使用的操作

    這篇文章主要介紹了Java catch與throw同時使用的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 自己動手寫的mybatis分頁插件(極其簡單好用)

    自己動手寫的mybatis分頁插件(極其簡單好用)

    最近做了個項目,需要用到mybatis分頁功能,網(wǎng)上找了很多插件,都不太合適,于是就自己動手寫了個mybatis分頁插件功能,非常不錯,代碼簡單易懂,需要的朋友參考下吧
    2016-11-11
  • Spring Cache原理解析

    Spring Cache原理解析

    Spring Cache是一個框架,它提供了基于注解的緩存功能,使得開發(fā)者可以很方便地將緩存集成到他們的應用程序中,這篇文章主要介紹了Spring Cache原理解析,需要的朋友可以參考下
    2024-05-05
  • Java中正則表達式 .* 的含義講解

    Java中正則表達式 .* 的含義講解

    這篇文章主要介紹了Java中正則表達式 .* 的含義,通過舉例說明了正則表達式*,+,?的區(qū)別,本文給大家講解的非常詳細,需要的朋友可以參考下
    2023-05-05
  • 實例講解Java并發(fā)編程之變量

    實例講解Java并發(fā)編程之變量

    這篇文章主要介紹了實例講解Java并發(fā)編程之變量,本文講解了編寫線程安全需要關(guān)心的共享變量和可變變量,需要的朋友可以參考下
    2015-04-04

最新評論