0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

初學(xué)者必看的SpringBoo自動裝配原理3

jf_78858299 ? 來源:CSDN ? 作者:CC_且聽風(fēng)吟 ? 2023-04-07 11:03 ? 次閱讀

6. My自動裝配

看到這里又自然會產(chǎn)生疑問:不會吧,上面可都是自動裝配啊,我在配置文件或者使用注解都配置了變量的值,然后加個(gè)@Autowired注解就OK了,spring也是幫我自動去裝配。

再高端一點(diǎn)話,我就把XML文件寫成JavaConfig配置類,然后使用@Configuration注解,這樣也能自動裝配,這不是很nice了嗎?

6.1 自動裝配之再思考

我的理解,上面的自動裝配,我們至少要寫一個(gè)配置文件,無論是什么形式,我們都至少需要一個(gè)文件把它全部寫下來,就算這個(gè)文件的內(nèi)容是固定的,但是為了裝配這個(gè)對象,我們不得不寫。

我們甚至都可以做成模板了,比如我在學(xué)習(xí)spring框架整合時(shí),把經(jīng)常寫的都搞成了模板:

有了這些模板,我們只需要點(diǎn)點(diǎn)點(diǎn),再進(jìn)行修改,就能用了。

這樣做確實(shí)很好,可是對于越來越成型的項(xiàng)目體系,我們每次都搞一些重復(fù)動作,是會厭煩的。而且面對這么多xml配置文件,我太難了。

于是我有了一個(gè)想說但不敢說的問題:

我一個(gè)配置文件都不想寫,程序還能照樣跑,我只關(guān)心有我需要的組件就可以了,我只需要關(guān)注我的目標(biāo)就可以了, 我想打開一個(gè)工程之后可以1秒進(jìn)入開發(fā)狀態(tài),而不是花3小時(shí)寫完配置文件(2.5小時(shí)找bug) 希望有個(gè)東西幫我把開始之前的準(zhǔn)備工作全做了,即那些套路化的配置,這樣在我接完水之后回來就可以直接進(jìn)行開發(fā)。

說到這里,想必大家都懂了:SpringBoot

6.2 一個(gè)例子

讓我們在偷懶的道路上繼續(xù)前進(jìn)。

來看下面這個(gè)例子:

仍然是A類和B類,其中A類仍然引用了B類,我們給A類組件起id=“a”,B類組件起id=“b”

@Component("a")
public class A {
    @Value("我是AAA")
    private String name;
    @Autowired
    private B b;
}

@Component("b")
public class B {
    @Value("我是BBB")
    private String name;
}

可以看到我們使用了@Autowired注解來自動注入b,測試類如下:

@Test
public void test(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyAutoConfig.class);
A aaa = ac.getBean("a", A.class);
System.out.println(aaa);
}

細(xì)心的同學(xué)已經(jīng)發(fā)現(xiàn)了:我們這里使用了AnnotationConfigApplicationContext這個(gè)JavaConfig配置類會使用到的加載類,于是我們順利成章地點(diǎn)開它所加載的MyAutoConfig類文件

文件內(nèi)容如下:

@Configuration
@MyEnableAutoConfig
public class MyAutoConfig {
    // bean 都去哪了 ???
}

what? 我要聲明的Bean對象都去哪了(注意:這里的applicationContext.xml是空的)?

讓我們運(yùn)行test:

A(name=我是AAA, b=B(name=我是BBB))

竟然運(yùn)行成功了,這究竟是為什么?(元芳,你怎么看?)

細(xì)心的同學(xué)已經(jīng)發(fā)現(xiàn)了:@MyEnableAutoConfig是什么注解?我怎么沒有這個(gè)注解

讓我們點(diǎn)進(jìn)@MyEnableAutoConfig一探究竟:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyImportSelector.class)   // 導(dǎo)入bean定義
public @interface MyEnableAutoConfig {
}

原來如此!你是用了@Import注解導(dǎo)入了Bean定義對吧,注釋都寫著呢!

可是客官,@Import導(dǎo)入bean定義是沒錯(cuò),但是它導(dǎo)入的是MyImportSelector這個(gè)bean,不是A也不是B啊…

6.3 @Import注解

@Import的功能就是獲取某個(gè)類的bean對象,他的使用形式大致如下:

@Import(A.class)
@Import(MyImportBeanDefinitionRegister.class)
@Import(MyImportSelector.class)

6.3.1 @Import(A.class)

第一種形式@Import(A.class),是最簡單易懂的形式

我們需要哪個(gè)Bean定義,直接Import他的class即可

6.3.2 @Import(MyImportBeanDefinitionRegister.class)

第二種形式@Import(MyImportBeanDefinitionRegister.class)

傳遞了一個(gè)bean定義注冊器,這個(gè)注冊器的具體內(nèi)容如下:

public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        
        RootBeanDefinition aDef = new RootBeanDefinition(A.class);
        registry.registerBeanDefinition("a", aDef);
        
    }
}

這個(gè)注冊器實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口,并且重寫了里面的registerBeanDefinitions方法

看他做了什么事:創(chuàng)建了一個(gè)新的bean定義,他的類型就是A,然后把這個(gè)bean定義注冊到BeanDefinitionMap(還記得吧?。├锩妫琸ey值我們可以人為設(shè)置,這里就設(shè)置成"a"

這樣在傳遞一個(gè)注冊器的時(shí)候,我們就可以把注冊器中新增的bean定義注冊進(jìn)來使用

6.3.3 @Import(MyImportSelector.class)

可以看到,這種使用方式就是我們剛才的注解中使用的方式

他傳遞了一個(gè)叫MyImportSelector的類,這個(gè)類依然是我們自己定義的,具體內(nèi)容如下:

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 導(dǎo)入配置類
        return new String[]{"config.MyConfig"};
    }
}

這個(gè)類實(shí)現(xiàn)了ImportSelector接口,并且重寫了selectImports方法,返回一個(gè)字符串?dāng)?shù)組

我們可以看到,返回的字符串?dāng)?shù)組中是我們要導(dǎo)入類的全類名

這個(gè)Importer返回的類如果是組件bean對象,就會被加載進(jìn)來使用;如果是一個(gè)配置類,就會加載這個(gè)配置類

第三種和第二種的區(qū)別是第三種可以一次性寫很多類,而且比較簡潔,只需要清楚類的全包名即可。而第二種方式需要自己清楚包類名,手動創(chuàng)建bean定義,然后手動加入BeanDefinitionMap。

6.4 例子的研究

我們打開MyImportSelector,發(fā)現(xiàn)里面赫然寫著幾個(gè)大字:

return new String[]{"config.MyConfig"};

然后我們找到config.MyConfig類,發(fā)現(xiàn)這個(gè)類竟然就是我們剛才寫的JavaConfig版本的配置文件:

@Configuration
public class MyConfig {
    @Bean
    public A a(){
        return new A();
    }

    @Bean
    public B b(){
        return new B();
    }
}

加載這個(gè)MyConfig配置類,就相當(dāng)于加載了A和B兩個(gè)Bean定義

喂!你是不是搞我!繞了一大圈,怎么還是加載這個(gè)配置文件啊!這個(gè)配置文件明明就是我自己寫的。

總結(jié)一下,我們這個(gè)例子大概繞了這些過程:

6.5 將偷懶進(jìn)行到底

"沒有會偷懶的人解決不掉的問題“ —— 魯迅

上面的例子也沒有多大優(yōu)化啊,我怎么覺得更加麻煩了?不但繞了一大圈,定義了許多新東西,到最后還是加載了我寫好的JavaConfig類,說到底我不是還在寫javaConfig類嗎…

但是你注意到?jīng)]有:有了上面的機(jī)制,我只需要把JavaConfig類寫一次,然后放在某個(gè)地方,在MyImportSelector中加入這個(gè)地方的全包名路徑,下次用的時(shí)候直接導(dǎo)入最頂層的MyAutoConfig類,所有有關(guān)這個(gè)部件我需要的東西,就全部自動整理好了,甚至比鼠標(biāo)點(diǎn)點(diǎn)點(diǎn)添加代碼模板還要快!

我突然有了個(gè)很棒的想法,不知道你有了沒有 。

如果你開始有點(diǎn)感覺了,就會自然提出另一個(gè)問題:我這樣做確實(shí)可以提高效率,但是一段代碼里寫入我自己定制的內(nèi)容,每次更改起來不是太費(fèi)勁了嗎?

想到這里,我就不禁回想起使用JDBC的時(shí)候,在代碼里改SQL語句的痛苦了,那真是生不如死…這種情況就構(gòu)成了硬編碼的行為,是不好的。

我們自然會想到:要是我創(chuàng)建一個(gè)配置文件properties來專門保存我這個(gè)需求所使用的bean對象,然后使用的時(shí)候在MyImportSelector中讀取配置文件并且返回全包名,不就更加nice了嗎?

于是MyImportSelector中的代碼又改成了下面這樣:

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
        Properties properties = MyPropertyReader.readPropertyForMe("/MyProperty.properties");
        String strings = (String) properties.get(MyEnableAutoConfig.class.getName());
       
        return new String[]{strings};
    }
}

其中MyPropertyReader是我們自己新創(chuàng)建的用于讀取properties文件的工具類

之所以要自己再定義這樣一個(gè)工具類,是為了以后在其中可以做一些其他操作(比如:去重、預(yù)檢查)

public class MyPropertyReader {
    public static Properties readPropertyForMe(String path){
        Properties properties = new Properties();
        try(InputStream sin = MyPropertyReader.class.getResourceAsStream(path)){
            properties.load(sin);
        }catch (IOException e){
            e.printStackTrace();
            System.out.println("讀取異常...");
        }
        return properties;
    }
}

我們的配置文件里面這么寫:

anno.MyEnableAutoConfig=config.MyConfig

可以看到,key是注解@MyEnableAutoConfig的類名,也就是根據(jù)這個(gè)注解,就會導(dǎo)入后面的MyConfig這個(gè)Bean,這個(gè)Bean就是我們的配置文件

如此一來我們讀取這個(gè)配置文件,然后加載跟這個(gè)注解名稱相符的value(即JavaConfig配置文件),就相當(dāng)于我們在代碼里手寫的"config.MyConfig",只不過現(xiàn)在的形式已經(jīng)發(fā)生了巨大的變化:我們添加或者刪除一個(gè)配件,完全只需要修改MyProperty.properties這個(gè)配置文件就行了!

至此,無論是添加或者刪除組件,無非是在配置文件中加上或者刪除一行的問題了。

讓我們在更新之后運(yùn)行程序,可以看到成功拿到了配置文件的全類名

程序的運(yùn)行當(dāng)然也是沒問題的:

A(name=我是AAA, b=B(name=我是BBB))

到此,我仿佛又領(lǐng)悟了一些東西。。。

我的配置文件好像活了,在我需要的時(shí)候他會出現(xiàn),在我不需要的時(shí)候只需要在配置文件里面給他”打個(gè)叉“,他自己就跑開了

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    335

    瀏覽量

    14278
  • 源碼分析
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    5537
  • 自動裝配
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    641
收藏 人收藏

    評論

    相關(guān)推薦

    protel技術(shù)大全--初學(xué)者必看

    protel技術(shù)大全--初學(xué)者必看。
    發(fā)表于 08-04 10:36

    PSOC1初學(xué)者必看的10個(gè)實(shí)例

    PSOC1初學(xué)者必看的10個(gè)實(shí)例
    發(fā)表于 11-19 16:33

    MATLAB入門教程-初學(xué)者必看

    MATLAB入門教程-初學(xué)者必看
    發(fā)表于 06-28 15:39

    Linux初學(xué)者必看!??!

    Linux初學(xué)者必看!?。?/div>
    發(fā)表于 01-07 21:35

    單片機(jī)入門秘籍,初學(xué)者必看

    初學(xué)者必看的單片機(jī)秘籍
    發(fā)表于 04-29 16:10

    PCB LAYOUT初學(xué)者必看

    PCBLAYOUT技術(shù)大全---初學(xué)者必看! PROTEL相關(guān)疑問 1.原理圖常見錯(cuò)誤: (1)ERC報(bào)告管腳沒有接入信號: a.創(chuàng)建封裝時(shí)給管腳定義了I/O屬性; b.創(chuàng)建元件或放置元件時(shí)修改了不一致的grid屬性
    發(fā)表于 09-13 15:23 ?0次下載

    PSOC1初學(xué)者5個(gè)實(shí)驗(yàn),針對初學(xué)者的實(shí)驗(yàn)

    PSOC1初學(xué)者5個(gè)實(shí)驗(yàn),針對初學(xué)者的實(shí)驗(yàn)
    發(fā)表于 10-16 09:33 ?14次下載
    PSOC1<b class='flag-5'>初學(xué)者</b>5個(gè)實(shí)驗(yàn),針對<b class='flag-5'>初學(xué)者</b>的實(shí)驗(yàn)

    初學(xué)者必看的基本電子技術(shù)概念

    初學(xué)者必看的基本電子技術(shù)概念
    發(fā)表于 05-17 11:41 ?0次下載

    初學(xué)者必看的電源測試項(xiàng)目要點(diǎn)及教程

    初學(xué)者必看的電源測試項(xiàng)目要點(diǎn)及教程
    發(fā)表于 07-01 14:09 ?29次下載

    初學(xué)者必看的LABVIEW工程師編程經(jīng)驗(yàn)

    初學(xué)者必看的LABVIEW工程師編程經(jīng)驗(yàn)
    發(fā)表于 07-12 14:24 ?29次下載

    ARM與嵌入式linux入門的建議(初學(xué)者必看)

    ARM與嵌入式linux入門的建議(初學(xué)者必看)(嵌入式開發(fā)培訓(xùn)怎么樣)-該文檔為ARM與嵌入式linux入門的建議(初學(xué)者必看)總結(jié)文檔,是一份很不錯(cuò)的參考資料,具有較高參考價(jià)值,感
    發(fā)表于 08-04 10:02 ?15次下載
    ARM與嵌入式linux入門的建議(<b class='flag-5'>初學(xué)者</b><b class='flag-5'>必看</b>)

    初學(xué)者必看的單片機(jī)程序匯總

    初學(xué)者必看的單片機(jī)程序匯總
    發(fā)表于 09-15 14:33 ?49次下載

    初學(xué)者必看SpringBoo自動裝配原理1

    學(xué)習(xí)SpringBoot,絕對避不開自動裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面的一些總結(jié)都是結(jié)合個(gè)人理解和實(shí)踐得出的,如果有錯(cuò)誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?582次閱讀
    <b class='flag-5'>初學(xué)者</b><b class='flag-5'>必看</b>的<b class='flag-5'>SpringBoo</b><b class='flag-5'>自動</b><b class='flag-5'>裝配</b>原理1

    初學(xué)者必看SpringBoo自動裝配原理2

    學(xué)習(xí)SpringBoot,絕對避不開自動裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面的一些總結(jié)都是結(jié)合個(gè)人理解和實(shí)踐得出的,如果有錯(cuò)誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?518次閱讀

    初學(xué)者必看SpringBoo自動裝配原理4

    學(xué)習(xí)SpringBoot,絕對避不開自動裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面的一些總結(jié)都是結(jié)合個(gè)人理解和實(shí)踐得出的,如果有錯(cuò)誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?590次閱讀
    <b class='flag-5'>初學(xué)者</b><b class='flag-5'>必看</b>的<b class='flag-5'>SpringBoo</b><b class='flag-5'>自動</b><b class='flag-5'>裝配</b>原理4