經過前文的學習,我們知道基于XML的顯式配置就是采用XML顯式配置Spring容器,自然而然的,基于Java的顯式配置則是采用Java這種編程語言顯式配置Spring容器,至于能用Java怎么配置,讓我們趁熱打鐵,緊接前文,看看同樣的專案能用基于Java的顯式配置怎么實作,進而學習基于Java的顯式配置的基礎知識,為此,請打開前文實作的music-player專案,新建AppConfig類,修改如下:
1 package com.dream; 2 3 import org.springframework.context.annotation.*; 4 5 @Configuration 6 public class AppConfig { 7 }
乍眼一瞧,大家肯定得犯嘀咕:“咋寫了個啥也沒有的類咧!”可是當我們靜下心來仔細瞧上一瞧,就會驚人地發現這個荒蕪的類上有個神秘的@Configuration注解,
這是怎么回事呢?
原來,@Configuration是Spring提供的一個注解,這個注解可以把某個類標為配置類,使之具有向Spring容器提供配置資訊的能力,由此可見,AppConfig既不是一個啥也沒有的類,也不是一個普通的類,而是一個具有@Configuration注解的配置類,只因我們尚未往類里添加配置資訊,所以空落落的,既然這樣,就讓我們敲些代碼充實一下該類,如下所示:
1 package com.dream; 2 3 import org.springframework.context.annotation.*; 4 5 @Configuration 6 public class AppConfig { 7 @Bean(name = "music") 8 public Music produceMusic() { 9 var music = new Music(); 10 music.setMusicName("執著"); 11 return music; 12 } 13 14 @Bean(name = "player") 15 public Player producePlayer() { 16 var music = this.produceMusic(); 17 var player = new Player(); 18 player.setMusic(music); 19 return player; 20 } 21 }
代碼非常簡單,就實作了兩個方法:一個方法能夠創建Music物件;一個方法能夠創建Player物件,需要特別留意的是,這兩個方法無一例外,都帶有一個神秘的@Bean注解,
這是怎么回事呢?
原來,@Bean也是Spring提供的一個注解,這個注解可以把某個方法標為配置方法,使之能被Spring應用背景關系發現之后進行呼叫,從而創建Bean,@Bean注解有個常用的name屬性,用于指定Bean的id,其值默認是與之相關的方法的方法名,
于是我們知道了,Spring應用背景關系加載AppConfig配置類之后,發現produceMusic方法帶有@Bean(name="music")注解,于是呼叫produceMusic方法創建一個型別為Music,id為music的Bean,發現producePlayer方法帶有@Bean(name="player")注解,于是呼叫producePlayer方法創建一個型別為Player,id為player的Bean,至于Spring應用背景關系怎樣加載配置類,請看以下代碼:
1 package com.dream; 2 3 import org.springframework.context.annotation.*; 4 5 public class Main { 6 public static void main(String[] args) { 7 try (var context = new AnnotationConfigApplicationContext(AppConfig.class)) { 8 var player = context.getBean("player", Player.class); 9 player.play(); 10 player.pause(); 11 } 12 } 13 }
這里用到AnnotationConfigApplicationContext,AnnotationConfigApplicationContext是Spring實作的另外一種Spring應用背景關系,能夠加載配置類,呼叫配置方法創建Bean,其建構式簽名如下:
public AnnotationConfigApplicationContext(Class<?>... componentClasses)
這個構建函式接受一個Class<?>... 型別的引數,用于告訴Spring應用背景關系能從哪些配置類里加載配置資訊,于是,我們創建AnnotationConfigApplicationContext物件的時候傳入AppConfig.class,告訴AnnotationConfigApplicationContext加載AppConfig配置類,呼叫AppConfig配置類里的配置方法創建Bean,
于是,Spring應用背景關系加載配置類之后順利完成了Bean的創建,這些Bean存在Spring應用背景關系中,由Spring應用背景關系管理著,我們只需呼叫getBean方法獲取id為player,型別為Player的Bean,隨后呼叫Bean的play方法播放音樂,pause方法暫停音樂即可實作音樂播放器,現在運行一下程式,輸出如下:
程式是順利跑起來了,同時我們也開始困惑了,前文曾經提及,Spring應用背景關系創建的Bean默認是單例的,可是,Spring應用背景關系呼叫配置方法創建Bean時,不是呼叫一次方法就創建一個物件,呼叫兩次方法就創建兩個物件嗎?如此,Spring容器創建的Bean怎么可能還是單例的呢?
為了解開這個迷題,讓我們修改一下AppConfig類,添加producePlayer_2方法如下:
1 package com.dream; 2 3 import org.springframework.context.annotation.*; 4 5 @Configuration 6 public class AppConfig { 7 @Bean(name = "music") 8 public Music produceMusic() { 9 var music = new Music(); 10 music.setMusicName("執著"); 11 return music; 12 } 13 14 @Bean(name = "player") 15 public Player producePlayer() { 16 var music = this.produceMusic(); 17 var player = new Player(); 18 player.setMusic(music); 19 return player; 20 } 21 22 @Bean(name="player_2") 23 public Player producePlayer_2() { 24 Music music = this.produceMusic(); 25 Player player = new Player(); 26 player.setMusic(music); 27 return player; 28 } 29 }
現在,producePlayer和producePlayer_2方法都能創建player物件,并且創建player物件時都會呼叫produceMusic方法創建music物件進行音樂的注入,于是問題來了,producePlayer方法呼叫produceMusic方法創建的music物件和producePlayer_2方法呼叫produceMusic方法創建的music物件是同一個嗎?
當然是的,實際上,Spring應用背景關系瞧見@Configuration注解之后并不會直接加載AppConfig配置類,而是基于AppConfig配置類生成一個代理類;之后又把帶有@Bean注解的配置方法生成代理方法,因此,每次呼叫produceMusic方法創建music物件的時候,并不是直接呼叫produceMusic方法創建music物件,而是呼叫Spring應用背景關系生成的代理類里的代理方法進行創建,代理方法創建Bean之前會先判斷一下即將創建的物件Spring應用背景關系里是不是已經有了,如果已經有了,則直接回傳Spring應用背景關系里的物件,不再創建,如果Spring應用背景關系里還沒有這個物件,則呼叫配置方法進行創建,由是我們的困惑解開了,Spring應用背景關系加載配置類之后創建的Bean默認還是單例的,
那么,producePlayer方法創建的player物件和producePlayer_2方法創建的player物件也是同一個物件嗎?
當然不是,為什么呢?因為這里定義了兩個方法,不同的方法運行不同的代碼創建的Bean當然是不同的,至于代理,則是Java這門編程語言的一個高級特性,超出本書的討論范圍,如果大家對此不太了解又想深入學習的話,建議大家閱讀一下關于代理的Java書籍或文章,這里不作介紹,
至此,基于Java的顯式配置的基礎知識介紹完了,前文曾經提及,除了顯式配置,Spring還提供了自動配置,令人興奮的是,自動配置還是一種遠比顯式配置更為迷人的配置方式,至于自動配置有多迷人,我們將在下一章進行介紹,歡迎大家繼續閱讀,謝謝大家!
回傳目錄
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/335084.html
標籤:其他
