透過Spring源碼查看Bean的命名轉(zhuǎn)換規(guī)則圖文詳解
前言
近期在寫Spring項(xiàng)目的時(shí)候,需要通過注解的形式去替代之前直接將Bean存放在Spring容器這種方式,以此來簡(jiǎn)化對(duì)于Bean對(duì)象的操作,但是這樣無法通過準(zhǔn)確的Id去獲取到相應(yīng)的Bean對(duì)象了
測(cè)試觀察
首先,如果要將指定的對(duì)象存放到Spring中,在Spring的配置文件中的掃描包路徑一定不能錯(cuò),這樣我們?cè)谶@個(gè)包中所包含的類前加上【五大類注解】,就可以將對(duì)象存儲(chǔ)到Spring中的
<content:component-scan base-package="com.spring.demo"></content:component-scan>

然后我便在這個(gè)包下寫了個(gè)UserController 類,并且加上了【@Controller】注解,此時(shí)Spring在加載的時(shí)候就會(huì)存儲(chǔ)改對(duì)象
@Controller
public class UserController {
public void SayHello(){
System.out.println("do SayHello()");
}
}此時(shí)看到,我在App類中去獲取到了這個(gè)Bean對(duì)象,而且使用的是【名稱 + 類名】的形式,這種形式就可以防止Spring中存儲(chǔ)多個(gè)Bean對(duì)象而造成的沖突問題
但是呢,我就卡在了這里,不知道該去寫什么名稱?因?yàn)楦緵]有在Spring中寫明Id值

首先我想到的是這個(gè)名稱會(huì)不會(huì)就是類名呢?但是在我進(jìn)行嘗試之后卻發(fā)現(xiàn)并不是這樣,編譯器報(bào)出了異常說No bean named 'UserController' available

然后我又想到了Java的命名規(guī)范是【小駝峰】,一般去通過這個(gè)類實(shí)例化對(duì)象的時(shí)候都是將首字母進(jìn)行一個(gè)小寫,其余不變,于是當(dāng)我使用這個(gè)名稱進(jìn)行傳遞的時(shí)候,程序運(yùn)行就沒有問題了

那我首先猜測(cè)它的命名就是這樣規(guī)定的,但是有沒有特例呢?
此時(shí)我又去定義了一個(gè)類,將其類名取成了兩個(gè)大寫字母開頭的,看看這樣子的命名是否還會(huì)以【小駝峰】的形式去進(jìn)行轉(zhuǎn)換
@Controller
public class SController {
public void SayHello(){
System.out.println("do SayHello()");
}
}但是當(dāng)我在看運(yùn)行結(jié)果的時(shí)候,卻發(fā)現(xiàn)這樣小駝峰的形式似乎行不通了

但是當(dāng)我在將名稱改回【類名】的時(shí)候,卻發(fā)現(xiàn)又可以運(yùn)行了,這是為什么呢?里面的轉(zhuǎn)換規(guī)則又是怎樣的?這需要我再去研究一番??

原理探究
通過上面的測(cè)試可以看出,Spring對(duì)于這個(gè)Bean對(duì)象的命名轉(zhuǎn)換是存在一定規(guī)則的,因?yàn)?u>【在Spring中,約定大于俗成】
接下去我就通過查看Spring源碼的方式帶讀者來探究一下到底這個(gè)Spring內(nèi)部對(duì)于這個(gè)Bean的命名轉(zhuǎn)換規(guī)則是怎樣的,雖然Spring框架的代碼都是開源的,但是要精準(zhǔn)地找到對(duì)應(yīng)想要的代碼邏輯可不簡(jiǎn)單,需要層層深入地進(jìn)行探訪
1、首先第一步,我們可以按兩下【shift】鍵,便會(huì)跳出IDEA的搜索框,在這個(gè)里面你可以去搜尋當(dāng)前項(xiàng)目中所有的類、接口,以查看它們的內(nèi)部實(shí)現(xiàn)。然后我便發(fā)現(xiàn)了一個(gè)類叫做AnnotationBeanNameGenerator,翻譯一下即為【注釋Bean名稱生成器】,那我猜測(cè)命名規(guī)范的代碼邏輯可能就在這個(gè)類中

2、當(dāng)我們進(jìn)入到這個(gè)類后,就可以去尋找其對(duì)應(yīng)的方法了,那個(gè)方法是和BeanName有關(guān)聯(lián)的,首先點(diǎn)擊右側(cè)的【結(jié)構(gòu)】我們便可以看到這個(gè)類中到底有哪些方法,那一看我們就可以觀察到有generateBeanName()這個(gè)方法,點(diǎn)到對(duì)應(yīng)的方法后再進(jìn)行觀察,便發(fā)現(xiàn)其最后返回時(shí)又去調(diào)用了一個(gè)方法,于是我繼續(xù)按住Ctrl鍵點(diǎn)進(jìn)去

點(diǎn)進(jìn)去發(fā)現(xiàn)里面又是一個(gè)方法,一些復(fù)雜的邏輯其實(shí)就是以這樣一種嵌套的形式進(jìn)行的,各個(gè)類、接口之間的方法調(diào)來調(diào)去

然后看到這是下面的這個(gè)方法buildDefaultBeanName()生成默認(rèn)Bean名稱

最后的話我們看到它在return的時(shí)候似乎又通過一個(gè)類名去調(diào)用了一個(gè)方法,然后傳入了這個(gè)ClassName,那我繼續(xù)點(diǎn)進(jìn)去后就發(fā)現(xiàn)我似乎已經(jīng)不處于Spring框架的源碼中了,而是來到了JDK中
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char[] chars = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}我們可以點(diǎn)擊右上角的這個(gè)按鈕【選擇打開的文件】去找到這個(gè)類所對(duì)應(yīng)的位置

最后我這邊順騰摸瓜地去查找就看到這個(gè)類是java.deskop包下的一個(gè)類,那么我們?cè)诓榭碨pring源碼的時(shí)候最終還是來到了JDK下,這個(gè)可以說明一點(diǎn):Bean的命名并不是亂取的,而是使用JDK的一個(gè)命名標(biāo)準(zhǔn)去進(jìn)行命名的

然后我們就可以去看看JDK中對(duì)于命名的規(guī)范到底是怎樣的??
可以看到很明顯的這里是有兩種情況,若是首字母和第二個(gè)字母都是大寫的話,那就返回原來的名稱;第二種情況則是將字符串首先轉(zhuǎn)換成了字符數(shù)組,然后再將第一位變成小寫
那看到這里的話其實(shí)我已經(jīng)是明白了,原來Spring對(duì)于Bean的這個(gè)命名規(guī)則是這樣的

總結(jié)一下
最后的話我們來總結(jié)一下本次查看源碼的收獲吧??
通過查看Spring的源碼我們進(jìn)入到了JDK中,經(jīng)過代碼的閱讀將Bean的命名轉(zhuǎn)換總結(jié)了以下兩點(diǎn)
默認(rèn)情況:使用原類名首字母小寫就能讀取到Bean對(duì)象特例:如果首字母和第二字母都是大寫的情況下,那么Bean名稱就是原類名
在學(xué)習(xí)Spring框架的過程中,初學(xué)者難免會(huì)遇到不理解的地方,因?yàn)镾pring是一個(gè)IoC容器,會(huì)通過DI依賴注入的形式幫我們自動(dòng)地去管理對(duì)象,所以內(nèi)部的細(xì)節(jié)便不得而知,但我們可以通過【閱讀源碼】的方式來進(jìn)行理解,去看看大佬是怎么思考的??
到此這篇關(guān)于透過Spring源碼查看Bean的命名轉(zhuǎn)換規(guī)則的文章就介紹到這了,更多相關(guān)Bean命名轉(zhuǎn)換規(guī)則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring中Service注入多個(gè)實(shí)現(xiàn)類的方法詳解
這篇文章主要介紹了Spring中Service注入多個(gè)實(shí)現(xiàn)類的方法詳解,Spring是一個(gè)開源的Java框架,用于構(gòu)建企業(yè)級(jí)應(yīng)用程序,它提供了許多功能,如依賴注入、面向切面編程、數(shù)據(jù)訪問、Web開發(fā)等,需要的朋友可以參考下2023-07-07
java中 String和StringBuffer的區(qū)別實(shí)例詳解
這篇文章主要介紹了java中 String和StringBuffer的區(qū)別實(shí)例詳解的相關(guān)資料,一個(gè)小的例子,來測(cè)試String和StringBuffer在時(shí)間和空間使用上的差別,需要的朋友可以參考下2017-04-04
Spring Hibernate實(shí)現(xiàn)分頁(yè)功能
這篇文章主要為大家詳細(xì)介紹了Spring Hibernate實(shí)現(xiàn)分頁(yè)功能的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
Java實(shí)現(xiàn)數(shù)組的復(fù)制及深淺拷貝的常見方法總結(jié)
這篇文章主要為大家詳細(xì)介紹了Java中數(shù)組的復(fù)制及深淺拷貝的常見實(shí)現(xiàn)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2026-01-01
Java生成范圍內(nèi)隨機(jī)整數(shù)的三種方法
在Java中生成隨機(jī)數(shù)的場(chǎng)景有很多,下面這篇文章主要給大家介紹了關(guān)于Java生成范圍內(nèi)隨機(jī)整數(shù)的三種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Mybatis-Plus根據(jù)時(shí)間段去查詢數(shù)據(jù)的實(shí)現(xiàn)示例
這篇文章主要介紹了Mybatis-Plus根據(jù)時(shí)間段去查詢數(shù)據(jù)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

