Spring裝配bean基礎

Spring容器負責創(chuàng)建應用程序中的bean并通過DI來協(xié)調這些對象之間的關系,我們需要做的就是告訴Spring要創(chuàng)建哪些bean以及這些bean的依賴情況。
Spring提供了三種主要的裝配機制,選擇哪種方案很大程度上就是個人喜好的問題,你盡可以選擇自己最喜歡的方式。

1.隱式的bean發(fā)現(xiàn)機制和自動裝配

Spring從兩個角度來實現(xiàn)自動化裝配:

  • 組件掃描(component scanning):Spring會自動發(fā)現(xiàn)應用上下文中所創(chuàng)建的bean。
  • 自動裝配(autowiring):Spring自動滿足bean之間的依賴。
    ?首先,定義一個接口:
package soundsystem;
public interface CompactDisc {
        void play{};
}

以及,CompactDisc實現(xiàn)類SgtPeppers:

package soundsystem;
import org.springframework.stereotype.Component;
@Component("LonelyHeartsClub")  // or @Named
public class SgtPeppers implements CompactDisc {
          private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
          private String artist = "The Beatles";

          public void play() {
              System.out.println("Playing " + title + " by " + artist);
          }
}

需要注意的是,SgtPeppers類使用了@Component注解,這個簡單的注解表明該類會作為組件類,并告知Spring要為這個類創(chuàng)建一個id為LonelyHeartsClub的bean。不過,組件掃描默認是不啟用的。我們還需要顯式配置一下Spring,從而命令它去尋找?guī)в蠤Component注解的類,并為其創(chuàng)建bean。

   package soundsystem;
   import org.springframework.context.annotation.ComponentScan;
   import org.springframework.context.annotation.Configuration;

   @Configuration
   @ComponentScan
   public class CDPlayerConfig { 
}

CDPlayerConfig使用了@Configuration注解,表明這是一個spring的配置類,而@ComponentScan注解則能夠在Spring中啟用組件掃描功能。如果沒有其他配置的話,@ComponentScan默認會掃描與配置類相同的包。因為CDPlayerConfig類位于soundsystem包中,因此Spring將會掃描這個包以及這個包下的所有子包,查找?guī)в蠤Component注解的類。這樣的話,就能發(fā)現(xiàn)CompactDisc,并且會在Spring中自動為其創(chuàng)建一個bean。如果你想要將config類放入一個獨立的包中以方便管理,也可以為@ComponentScan傳入你想要作為掃描基礎包的包名,如:

 @ComponentScan("org.xxx.packagename")

或者

@ComponentScan(basePackages={"org.xxx.packagename","org.xxx.otherpackagename"})

來指定多個基礎包。
?為了以后方便重構(有可能改變包名),那么可以采用更加安全的方式

   @ComponentScan(basePackageClasses={abc.class, 123.class})

不再使用String類型的名稱來指定包,為basePackageClasses屬性所設置的數(shù)組中包含了類。這些類所在的包將會作為組件掃描的基礎包。
?如果你更傾向于使用XML來啟用組件掃描的話,那么可以使用Spring context命名空間的<context:component-scan>元素。

   <?xml version="1.0" encoding="UTF-8"?>
   <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:context="http://www.springframework.org/schema/context"   xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="package" />

顯然,在實際的項目開發(fā)中,bean之間的關系不會像上文所列舉的那樣簡單,不同的組件往往相互依賴來完成復雜的任務,所以,我們需要了解一下Spring自動化配置的另外一方面內容,那就是自動裝配。
?通過自動裝配,將一個CD注入到CDPlayer之中:

   package soundsystem;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.stereotype.Component;

   @Component // or @Named
   public class CDPlayer implements MediaPlayer {
     private CompactDisc cd;

     @Autowired // or @Inject
     public CDPlayer(CompactDisc cd) {
       this.cd = cd;
     }

     public void play() {
       cd.play();
     }
   }

構造器上添加了@Autowired注解,這表明當Spring創(chuàng)建CDPlayer bean的時候,會通過這個構造器來進行實例化并且會傳入一個實現(xiàn)了CompactDisc的bean。
?@Autowired注解不僅能夠用在構造器上,還能用在類的任何方法上。比如說,如果CDPlayer有一個insertDisc()方法,那么可以采用如下的注解形式進行自動裝配:

   @Autowired
   public insertDisc(CompactDisc cd) {
       this.cd = cd;
   }

如果沒有匹配的bean,那么在應用上下文創(chuàng)建的時候,Spring會拋出異常。為了避免異常的出現(xiàn),你可以將@Autowired的required屬性設置為false:

   @Autowired(required=false)
   public insertDisc(CompactDisc cd) {
       this.cd = cd;
   }

將required屬性設置為false時,Spring會嘗試執(zhí)行自動裝配,但是如果沒有匹配的bean的話,Spring將會讓這個bean處于未裝配的狀態(tài)。但是,把required屬性設置為false時,你需要謹慎對待。如果在你的代碼中沒有進行null檢查的話,這個處于未裝配狀態(tài)的屬性有可能會出現(xiàn)NullPointerException。

2.通過Java代碼裝配bean

大部分情況下組件掃描和自動裝配實現(xiàn)Spring的自動化配置是更為推薦的方式,但有時候自動化配置的方案行不通時,比如說,你想要將第三方庫中
的組件裝配到你的應用中,在這種情況下,是沒有辦法在它的類上添加@Component和@Autowired注解的,因此就不能使用自動化裝配的方案了。

讓我們修改一下CDPlayerConfig類:

   package soundsystem;
   import org.springframework.context.annotation.Configuration;

   @Configuration
   public class CDPlayerConfig { 
   }

我們去掉了@ComponentScan注解,意味著spring容器不再自動掃描我們帶有@Component(或@Named)注解的類了,下面我們將在CDPlayerConfig類中顯式地配置之前創(chuàng)建的類。
?我們在config類中加入以下代碼:

   package soundsystem;
   import org.springframework.context.annotation.Configuration;

   @Configuration
   public class CDPlayerConfig { 
      @Bean
      public CompactDisc sgtPeppers() {
            return new SgtPeppers();
      }
   }

@Bean注解會告訴Spring這個方法將會返回一個對象,該對象要注冊為Spring應用上下文中的bean。方法體中包含了最終產生bean實例的邏輯。bean的名字默認為方法名,如有需要,可以使用如下方法修改:

   @Bean(name="beanId")
   public CompactDisc sgtPeppers() {
          return new SgtPeppers();
   }

使用java配置類進行裝配同樣要考慮依賴注入的問題,下面就是一種聲明CDPlayer的可行方案:

   @Bean
   public CDPlayer cdPlayer() {
        return new CDPlayer(sgtPeppers());
   }

看起來,cdPlayer所依賴的CompactDisc是通過調用sgtPeppers()得到的,但情況并非完全如此。因為sgtPeppers()方法上添加了@Bean注解,Spring將會攔截所有對它的調用,并確保直接返回該方法所創(chuàng)建的bean,而不是每次都對其進行實際的調用,也就是說sgtPeppers仍然是單例的。
?但是上面的寫法有一個不足,那就是如果sgtPeppers()方法沒有定義在CDPlayerConfig中,而是定義在另一個config或xml配置文件中,cdPlayer方法是無法調用的,所以,這種方式并不合理,來看另一種方法:

   @Bean
   public CDPlayer cdPlayer(CompactDisc  compactDisc ) {
        return new CDPlayer(compactDisc );
   }

在這里,cdPlayer()方法請求一個CompactDisc作為參數(shù)。當Spring調用cdPlayer()創(chuàng)建CDPlayerbean的時候,它會自動裝配(不管以何種方式)一個CompactDisc到配置方法之中。然后,方法體就可以按照合適的方式來使用它。借助這種技術,cdPlayer()方法也能夠將CompactDisc注入到CDPlayer的構造器中,而且不用明確引用CompactDisc的@Bean方法。

再次強調一遍,帶有@Bean注解的方法可以采用任何必要的Java功能來產生bean實例。

3.通過XML裝配bean

// TODO

4.解決不同配置方式之間的依賴關系

現(xiàn)在,我們已經知道cdPlayer bean需要依賴于compactDisc bean,假如我們的cdPlayer bean依然由CDPlayerConfig來裝配,而compactDisc bean則改由CDConfig來裝配:

   package soundsystem;

   import org.springframework.context.annotation.Bean;
   import org.springframework.context.annotation.Configuration;

   @Configuration
   public class CDConfig {
     @Bean
     public CompactDisc compactDisc() {
       return new SgtPeppers();
     }
   }

一種方法就是在CDPlayerConfig中使用@Import注解導入CDConfig:

   package soundsystem;
   import org.springframework.context.annotation.Configuration;
   import org.springframework.context.annotation.Import;
   import org.springframework.context.annotation.Bean;

   @Configuration
   @Import(CDConfig.class)
   public class CDPlayerConfig { 
       @Bean
       public CDPlayer cdPlayer(CompactDisc  compactDisc ) {
            return new CDPlayer(compactDisc );
       }
   }

或者采用一個更好的辦法,也就是不在CDPlayerConfig中使用@Import,而是創(chuàng)建一個更高級別的SoundSystemConfig,在這個類中使用@Import將兩個配置類組合在一起:

package soundsystem;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;

@Configuration
@Import({CDPlayerConfig.class, CDConfig.class})
public class SoundSystemConfig {

}

同樣的,假如還有一部分bean定義在bean-config.xml中,則需要用@ImportResource注解導入:

package soundsystem;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;

@Configuration
@Import({CDPlayerConfig.class, CDConfig.class})
@ImportResource("classpath:bean-config.xml")
public class SoundSystemConfig {

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,786評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,899評論 6 342
  • 本章內容: 聲明Bean 構造器注入和Setter方法注入 裝配Bean 控制bean的創(chuàng)建和銷毀 任何一個成功的...
    謝隨安閱讀 1,655評論 0 9
  • 2.1 Spring配置的可選方案 Spring提供了三種主要的裝配機制: 1)在XML中進行顯示配置。2)在ja...
    如一諾然閱讀 498評論 0 1
  • 經常聽人說:想做就去做,別猶豫,否猶則豫一會就沒了做這件事的興趣了。 我曾經深以為是,可是隨著時間的推移, 年齡的...
    第十頁閱讀 346評論 0 1