spring 學習筆記(一)自動裝配

    Spring4.0版本有三種裝配方式,今天記錄的是第一種,也是用的最多的一種-自動裝配

    Spring從兩個角度實現自動裝配:

         1、組件掃描:Spring會自動發現應用上下文中所創建的bean。

         2、自動裝配:Spring自動滿足bean之間的依賴。

創建可被發現的bean

以cd和播放器爲例,首先創建一個cd的概念,定義一個cd的接口

package soundsystem;
public interface CompactDisc{
   void play();
}

       這個類中代碼很簡單,只有一個方法,作爲這個接口它定義了cd播放器對cd所能做的操作,這樣做的意義是將cd播放器的任意實現與cd本身的耦合降低到了最小的程度。

      我們還需要一個CompactDiscde的實現。

package soundsystem;
import org.springframework.stereotype.Component;
@Component
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);
    }
}

@component 該註解表明該類作爲組件類,並告知Spring要爲這個類創建bean。默認這個類的ID是sgtPeppers,也就是說將類的第一個字母變爲小寫。如果想爲這個bean設置不同的ID需要手動寫清楚,或者使用java的依賴注入規範@Named,在大多數場景中,它們是可以相互替換的。

@Component{"lonelyHeartsClub"}
@Named{"lonelyHeartsClub"}

組件掃描默認是不開啓的,需要顯示配置一下 Spring。

@ComponentScan 註解啓用了組件掃描

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

@Configuration
@ComponentScan
public class CDPlayerConfig { 
}

@ComponentScan註解默認會掃描與配置類相同的包,Spring會掃描這個包以及這個包下的所有子包。

通過xml配置的方法

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

接下來要簡單測試一下,使用junit測試工具。

package soundsystem;

import static org.junit.Assert.*;

import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {

  @Autowired
  private CompactDisc cd;
  
  @Test
  public void cdShouldNotBeNull() {
    assertNotNull(cd);
  }
}

這個類使用了SpringJUnit4ClassRunner,所以在測試開始的時候自動創建Spring的上下文。@ContextConfiguration會告訴它需要在CDPlayerConfig中加載配置。在這個配置中CD屬性部位null,如果它不爲null的話,就意味着Spring能夠發現CompactDisc類。

設置組件掃描基礎包

如果沒有設置@ComponentScan任何屬性,那麼會掃描配置類下面所有的包作爲基礎包。如果想掃描不同的包或者是掃描多個基礎包那麼就需要指定包。在@ComponeentScan的value屬性指名包的名稱

如果想更加清晰設置基礎包需要使用backPackages屬性,並且@basePagckages可以指定多個基礎包。

@Configuration
@ComponentScan{backPackages = "soundsystem","video"} 
public class CDPlayerConfig{}

在上面的例子中,基礎包是以String類型表示的,這是是可以的,但是這種類型是不安全的。如果重構代碼,那麼所指向的代碼可能會出現錯誤。這時候可以將其指定爲包中所包含的類或者接口

@Configuration
@ComponentScan{backPackagesClasses = "CDPlayer.class","DVDplayer.class"}
public class CDPlayerConfig{}
儘管在樣例中,爲basePackageClasses設置的是組件類,但是可以考慮在包中創建一個用來進行掃描的空標記接口(marker
interface)。通過標記接口的方式,依然能夠保持對重構友好的接口引用,但是可以避免引用任何實際的應用程序代碼(在稍後重構中,這些應用代碼有可能會從想要掃描的包中移除掉)。在應用程序中,如果所有的對象都是獨立的,彼此之間沒有任何
依賴,就像SgtPeppersbean這樣,那麼你所需要的可能就是組件掃描而已。但是,很多對象會依賴其他的對象才能完成任務。這樣的話,就需要有一種方法能夠將組件掃描得到的bean和它們的依賴裝配在一起。要完成這項任務,我們需要了解一下Spring自動化配置的另外一方面內容,那就是自動裝配。

通過爲bean添加註解實現自動裝配

自動裝配就是讓Spring自動滿足bean依賴的一種方法,在滿足依賴的過程中,會在Spring應用上下文中尋找匹配某個bean需求
的其他bean。爲了聲明要進行自動裝配,可以藉助Spring的@Autowired註解。

@Autowired註解不僅能夠用在構造器上,還能用在屬性的Setter方法上。比如說,如果CDPlayer有一個setCompactDisc()方法,那麼可以採用如下的註解形式進行自動裝配:

@Autowired
public void setCompactDisc(CompactDisc cd){ this.cd = cd;
}
在Spring初始化bean之後,它會儘可能得去滿足bean的依賴,在本例中,依賴是通過帶有@Autowired註解的方法進行聲明的,也就是setCompactDisc()。實際上,Setter方法並沒有什麼特殊之處。@Autowired註解可以用在類的任何方法上。假設CDPlayer類有一個insertDisc()方法,那麼@Autowired能夠像在setCompactDisc()上那樣,發揮完全相同的作用。


不管是構造器、Setter方法還是其他的方法,Spring都會嘗試滿足方法參數上所聲明的依賴。假如有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來。如果沒有匹配的bean,那麼在應用上下文創建的時候,Spring會拋出一個異常。爲了避免異常的出現,你可以將@Autowired的required屬性設置爲false。

將required屬性設置爲false時,Spring會嘗試執行自動裝配,但是如果沒有匹配的bean的話,Spring將會讓這個bean處於未裝配的狀態。但是,把required屬性設置爲false時,你需要謹慎對待。如果在你的代碼中沒有進行null檢查的話,這個處於未裝配狀態的屬性有可能會出現NullPointerException。如果有多個bean都能滿足依賴關係的話,Spring將會拋出一個異常,表明沒有明確指定要選擇哪個bean進行自動裝配。

@Autowired是Spring特有的註解。如果你不願意在代碼中到處使用Spring的特定註解來完成自動裝配任務的話,那麼你可以考慮將其替換爲@Inject。

下面將要驗證自動裝配

package soundsystem;

import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {

  @Rule
  public final StandardOutputStreamLog log = new StandardOutputStreamLog();

  @Autowired
  private MediaPlayer player;
  
  @Autowired
  private CompactDisc cd;
  
  @Test
  public void cdShouldNotBeNull() {
    assertNotNull(cd);
  }

  @Test
  public void play() {
    player.play();
    assertEquals(
        "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles\n", 
        log.getLog());
  }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章