最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

三種Spring BeanName生成器,你了解嗎

 更新時間:2023年09月12日 10:57:48   作者:江南一點雨  
無論我們是通過 XML 文件,還是 Java 代碼,亦或是包掃描的方式去注冊 Bean,都可以不設置BeanName,而Spring均會為之提供默認的 beanName,本文我們就來看看 Spring 中三種處理不同情況的 beanName生成器吧

1. BeanNameGenerator

Spring 中提供了一個名為 BeanNameGenerator 的接口,這個接口就只有一個需要實現(xiàn)的方法就是 generateBeanName,從名字就能看出來,這就是專門用來生成 beanName 的方法。

public?interface?BeanNameGenerator?{
?String?generateBeanName(BeanDefinition?definition,?BeanDefinitionRegistry?registry);
}

這個方法有兩個參數(shù):

  • definition:這個是要生成的 Bean 定義。
  • registry:這個是將來 BeanDefinition 的注冊器。

BeanNameGenerator 有三個不同的實現(xiàn)類,對應不同的處理場景:

  • AnnotationBeanNameGenerator:這個專門用來處理包掃描的時候掃到的 Bean,對于這些 Bean,其 name 屬性該如何處理,由這個類來解決,當然,小伙伴們都知道,通過 @Component/@Service/@Repository/@Controller 這些注解定義的 Bean,默認情況下,beanName 就是類名首字母小寫。
  • FullyQualifiedAnnotationBeanNameGenerator:這個繼承自 AnnotationBeanNameGenerator,并重寫了 AnnotationBeanNameGenerator#buildDefaultBeanName 方法,這個是使用類的全路徑來作為 Bean 的默認名稱。
  • DefaultBeanNameGenerator:這個是專門用來解決 XML 文件中定義的 Bean 如果沒有設置 beanName,那么就通過 DefaultBeanNameGenerator 來為其生成 beanName。

看了上面三個場景之后,可能有小伙伴發(fā)現(xiàn)一個 BUG,那么 @Bean 注解定義的 Bean,其 beanName 屬性是在哪里處理的呢?這個其實比較特殊,是當場處理的,沒用到 BeanNameGenerator,松哥后面單獨說。

接下來我們詳細看下上面這三個實現(xiàn)類。

2. AnnotationBeanNameGenerator

咱們直接來看最關鍵的 generateBeanName 方法吧:

@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);
}

這個方法首先判斷 definition 是否為 AnnotatedBeanDefinition 類型,根據(jù)我們前面文章對 BeanDefinition 的介紹(七種 BeanDefinition,各顯其能!),大家知道,AnnotatedBeanDefinition 的實現(xiàn)類主要是針對三種情況:@Bean 注解定義的 Bean、@Service/@Controller/@Component/@Repository 等注解標記的 Bean 以及系統(tǒng)的啟動配置類,如果是這三種情況,那么就去調(diào)用 determineBeanNameFromAnnotation 方法,這個方法會嘗試從注解中提取出來 beanName,如果不是上面三種情況,那么就調(diào)用 buildDefaultBeanName 方法去生成 beanName。

那我們先來看 determineBeanNameFromAnnotation 方法:

@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?strVal)?{
?????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;
}

這個方法首先會去獲取類上的注解信息,拿到 amd 之后,獲取到所有的注解類型,然后進行遍歷。

遍歷的時候,首先獲取到注解上的所有屬性 attributes,當 attributes 不為空的時候,繼續(xù)去讀取當前注解的元注解,并將讀取到的結果存入到 metaAnnotationTypesCache 集合中。這個是干嘛呢?大家知道,Spring 中用來標記 Bean 的注解大部分衍生自 @Component,甚至我們也可以自定義注解,那么如果自定義注解了,這個地方就沒法判斷了,因為每個人自定義出來的注解都不一樣。所以,萬變不離其宗,這里就去找各個注解的元注解。例如如果我們在類上添加的是 @Configuration,那么 @Configuration 的元注解有兩個,分別是 @Component 和 @Indexed。

接下來的 isStereotypeWithNameValue 方法就是判斷 type 是不是 @Component 或者 Jakarta 中自帶的 @ManagedBean、@Named,亦或者 metaTypes 里是否包含 @Component。如果確定是 @Component 衍生出來的注解,亦或者是 @ManagedBean、@Named 注解標記的 Bean,那么就將其 value 屬性讀取出來,作為 beanName,如果包含多個有效注解,且各自配置的 beanName 不一致,就會拋出異常。

例如下面這種情況:

@Configuration("j")
@Component("a")
public?class?JavaConfig?{
}

這兩個 beanName 不一致,運行時就會出錯。

同時,經(jīng)過上面的分析,小伙伴也看到了,我們其實可以通過自定義注解為 Bean 設置名稱,例如我有如下注解:

@Retention(RetentionPolicy.RUNTIME)
@Component
public?@interface?MyBeanName?{
????String?value()?default?"";
}

這個注解衍生自 @Component,那么它的用法如下:

@MyBeanName("f")
public?class?JavaConfig?{
}

那么 f 就是當前類生成的 beanName。

以上是從注解中去提取 beanName,但是注解中可能沒有提供 beanName,那么就得調(diào)用 buildDefaultBeanName 方法去自動生成了,如下:

protected?String?buildDefaultBeanName(BeanDefinition?definition,?BeanDefinitionRegistry?registry)?{
?return?buildDefaultBeanName(definition);
}
protected?String?buildDefaultBeanName(BeanDefinition?definition)?{
?String?beanClassName?=?definition.getBeanClassName();
?Assert.state(beanClassName?!=?null,?"No?bean?class?name?set");
?String?shortClassName?=?ClassUtils.getShortName(beanClassName);
?return?StringUtils.uncapitalizeAsProperty(shortClassName);
}

這個就很好懂了,先拿到 bean 的完整類名,然后提取出來 shortName,也就是去除包名之后的名字,然后首字母小寫之后返回。

這就是 @Component 注解體系下的 beanName 生成流程。

3. FullyQualifiedAnnotationBeanNameGenerator

FullyQualifiedAnnotationBeanNameGenerator 類只是重寫了 AnnotationBeanNameGenerator 的 buildDefaultBeanName 方法,如下:

@Override
protected?String?buildDefaultBeanName(BeanDefinition?definition)?{
?String?beanClassName?=?definition.getBeanClassName();
?Assert.state(beanClassName?!=?null,?"No?bean?class?name?set");
?return?beanClassName;
}

重寫后的方法就是獲取類的完整路徑返回。

FullyQualifiedAnnotationBeanNameGenerator 默認情況下并不會直接使用,需要自己手動配置,像下面這樣:

@Configuration
@ComponentScan(nameGenerator?=?FullyQualifiedAnnotationBeanNameGenerator.class)
public?class?JavaConfig?{
}

此時,生成的 Bean 的默認名稱就是類的全路徑了。

4. DefaultBeanNameGenerator

這個是專門用來處理 XML 中默認的 beanName 的。這個在最近錄制的 Spring 源碼視頻中已經(jīng)詳細介紹過了,這里就不再啰嗦了

5. @Bean 處理特殊情況

如果類是被 @Bean 注解標記的,那么處理情況就特殊一些,直接現(xiàn)場處理,方法在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod 位置:

private?void?loadBeanDefinitionsForBeanMethod(BeanMethod?beanMethod)?{
?//?Consider?name?and?any?aliases
?List<String>?names?=?new?ArrayList<>(Arrays.asList(bean.getStringArray("name")));
?String?beanName?=?(!names.isEmpty()???names.remove(0)?:?methodName);
?//?Register?aliases?even?when?overridden
?for?(String?alias?:?names)?{
??this.registry.registerAlias(beanName,?alias);
?}
}

從這里可以看到,如果一開始配置了 name 屬性,那么就把 names 集合中的第一個值拿出來作為 beanName,集合中的其他值則當作別名來處理,如果沒有配置 name 屬性值,那么就使用方法名作為 beanName。

到此這篇關于三種Spring BeanName生成器,你了解嗎的文章就介紹到這了,更多相關Spring BeanName生成器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 比較常用UML類圖幾種關系的小結

    比較常用UML類圖幾種關系的小結

    本文給大家總結了UML類圖中幾種比較常用的關系小總結,需要的朋友可以參考下
    2015-10-10
  • 一個Servlet是如何處理多個請求的?

    一個Servlet是如何處理多個請求的?

    以前我一直以為一個Servlet只能處理一個請求,后來發(fā)現(xiàn)是自己太菜了,可以借助攜帶一個參數(shù)來完成多個請求的處理,根據(jù)參數(shù)的不同,在核心的service方法中調(diào)用不同的業(yè)務方法,來實現(xiàn)處理多個servlet請求的目的,廢話不多說,直接上代碼,需要的朋友可以參考下
    2021-06-06
  • Java深入講解Object類常用方法的使用

    Java深入講解Object類常用方法的使用

    前面java繼承中說到的Object類是java中一個特殊的類,所有的類都是直接或者間接的繼承自Object類,即如果某個類沒有使用extends關鍵字則默認是java.lang.Object類的子類,所以所有的類都可以使用Object類中定義的方法,下面介紹Object類的常用方法
    2022-04-04
  • springsecurity中http.permitall與web.ignoring的區(qū)別說明

    springsecurity中http.permitall與web.ignoring的區(qū)別說明

    這篇文章主要介紹了springsecurity中http.permitall與web.ignoring的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • springboot編程式事務TransactionTemplate的使用說明

    springboot編程式事務TransactionTemplate的使用說明

    這篇文章主要介紹了springboot編程式事務TransactionTemplate的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java中集合遍歷的方法示例代碼展示

    Java中集合遍歷的方法示例代碼展示

    在 Java 編程中,集合(Collection)是用于存儲和操作一組對象的重要工具,無論是數(shù)組、列表(List)、集合(Set),還是映射(Map),它們都提供了在不同場景下靈活使用的數(shù)據(jù)結構,這篇文章主要介紹了Java中集合遍歷的方法示例代碼展示,需要的朋友可以參考下
    2024-08-08
  • Java 函數(shù)編程詳細介紹

    Java 函數(shù)編程詳細介紹

    這篇文章主要介紹了Java函數(shù)式編程,lambda表達式可以被認為是一個匿名函數(shù),可以在函數(shù)接口的上下文中使用。函數(shù)接口是只指定一個抽象方法的接口,下面來看文章的詳細內(nèi)容,需要的朋友可以參考下
    2021-11-11
  • 深入理解Java設計模式之適配器模式

    深入理解Java設計模式之適配器模式

    這篇文章主要介紹了JAVA設計模式之適配器模式的的相關資料,文中示例代碼非常詳細,供大家參考和學習,感興趣的朋友可以了解
    2021-11-11
  • restTemplate配置及使用過程

    restTemplate配置及使用過程

    本文介紹了在Java開發(fā)中使用HttpClient和OKHttp進行HTTP連接的復雜性,推薦使用Spring框架的RestTemplate進行簡化,RestTemplate支持多種HTTP連接方式,并提供了豐富的API進行GET、POST請求和文件上傳,文章還提供了具體的代碼示例
    2025-11-11
  • java尋找迷宮路徑的簡單實現(xiàn)示例

    java尋找迷宮路徑的簡單實現(xiàn)示例

    這篇文章主要介紹了java尋找迷宮路徑的簡單實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10

最新評論

贵德县| 广饶县| 玉林市| 双桥区| 林州市| 琼海市| 荥阳市| 澎湖县| 大冶市| 南澳县| 磴口县| 西乌珠穆沁旗| 珲春市| 阳山县| 濮阳县| 洛川县| 泗阳县| 抚远县| 南京市| 丘北县| 武穴市| 安达市| 龙胜| 洞头县| 于都县| 大同县| 曲松县| 泰安市| 顺义区| 从江县| 阜新市| 镇原县| 永胜县| 小金县| 扎赉特旗| 通州区| 商河县| 广平县| 桐柏县| 临夏县| 赤壁市|