1. 程式人生 > >Spring中bean的三種裝配機制之——自動裝配

Spring中bean的三種裝配機制之——自動裝配

基本介紹

  關於各種配置,從來沒搞懂過。但是覺得框架發展這麼快,而且結構這麼巨集大,其實現微觀上來講應該從來沒有一種標準方式、更沒有說是固定的幾種。比如Spring專有的@Component、@Autowired註解,大多數情況下都可以被javax.inject包下的@Named和@Inject代替。本博文彙總《Spring 實戰 第四版》2.1和2.2內容。
  自動裝配是使用spring滿足bean依賴的一種方法,滿足以來的過程中,spring會在應用上下文中為某個bean尋找其依賴的bean
  Spring中bean有三種裝配機制,分別是:
1. 在xml中顯示配置;
2. 在java中顯示配置;
3. 隱式的bean發現機制和自動裝配。
這裡我們主要講第三種:自動化的裝配bean。

自動化的裝配bean

  Spring的自動裝配需要從來能個角度來實現,或者說是兩個操作:
    1.元件掃描(component scanning):spring會自動發現應用上下文中所建立的bean;
    2.自動裝配(autowiring):spring自動滿足bean之間的依賴,也就是我們上篇博文說的IoC/DI
  元件掃描和自動裝配組合發揮巨大威力,使的顯示的配置降低到最少

一.bean自動裝配的基本方式及測試

  這裡以“光碟機”和“cd播放器”為例來介紹自動裝配的基本實現方式。假設我們有個光碟介面CompacDisc,其具體實現類為各個明星的專輯,實現如下:

package com.example.springboot.demo.soundsystem;

import org.springframework.stereotype.Component;

@Component//表明該類會作為元件類,告知spring為這個類建立bean
public class SgtPeppers implements CompactDisc {

    private String title="ye hui mei";
    private String artist="zhou jie lun";

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

  通過@Component告知Spring為SgtPeppers 建立bean是不夠的,我們還需要讓spring知道去哪裡掃描可能帶有@Component的類,盲目的全域性掃描是不可行的。這裡我們使用在配置類中使用@Component註解啟用元件掃描,也就是@Configuration+@ComponentScan。簡單的一逼,例項如下:

package com.example.springboot.demo.soundsystem;

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

/**
 * @author 杜艮魁
 * @date 2017/12/10
 */

@Configuration
@ComponentScan
public class CDPlayerConfig {
}

  在這裡@ComponentScan等同於@ComponentScan(“com.example.springboot.demo.soundsystem”)和@ComponentScan(basePackges=“com.example.springboot.demo.soundsystem”),即將基礎包設定為配置類所在的包,spring會掃描配置類所在的包及其子包
  除此之外,@Component和@ComponentScan還有諸如配置bean名稱、設定基礎包路徑、設定基礎包路經集合、使用類或介面標記基礎包所在位置等東西,稍後示例我們在展開講解。
  以上配置是否生效,我們使用一下示例測試:

package com.example.springboot.demo.soundsystem;

import org.junit.Test;
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;

import static org.junit.Assert.*;

/**
 1. @author 杜艮魁
 2. @date 2017/12/10
 */
@RunWith(SpringJUnit4ClassRunner.class)//告訴Spring在測試的時候建立應用上下文;
@ContextConfiguration(classes = CDPlayerConfig.class)//告訴測試程式在CDPlayerConfig類中載入配置
public class CDPlayerTest {

    @Autowired
    private CompactDisc compactDisc;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(compactDisc);
    }
}
//輸出:Process finished with exit code 0

  之所以輸出為“真”是因為:
  1.@RunWith(SpringJUnit4ClassRunner.class)告訴Spring在測試的時候建立應用上下文;
  2.@Configuration和@ComponentScan註解建立應用上下文時掃描到了同包下@Component註解的CompactDisc介面的實現類SgtPeppers,然後spring為其建立bean;
  3.@ContextConfiguration(classes = CDPlayerConfig.class)告訴測試程式在CDPlayerConfig類中載入配置

二.為bean命名

  bean的預設名稱為雷米給你的第一個字母小寫,即:

@Component
public class SgtPeppers implements CompactDisc {...}
同
@Component("sgtPeppers")//引號內名稱可以自定義
public class SgtPeppers implements CompactDisc {...}

我們可以自定義名稱,一共我們以後方便使用。

三.設定元件掃描的基礎包:集合、類/介面標識、同義替換及他們的相關測試

  配置類類名上只有一個@ComponentScan是不夠的,當我們想把配置類單獨放在一個包裡,而bean又不在其子包時,我們需要制定包路徑。更甚者bean不在同一個父親包中是,我們就要使用路徑集合來制定掃描的路徑。基本實現方式如下:
  1)包路徑法:

@ComponentScan("XXXX")
@ComponentScan(basePackages={"xx","yy"})

  2)類/介面定位法:當我們重構程式碼時,包路徑可能不在有效,此時我們可以指定一個類或者介面,將這些類/介面所在的包指定為基礎包,注意使用basePackageClasses屬性。實際使用中我們可以定義“空標記類(marker interface)”,而不一定甚至不應該使用實際的業務類。

@ComponentScan(basePackageClasses={demo.class})
五.為bean添加註解實現自動裝配

  在bean中宣告對依賴的bean進行自動裝配,我們可以藉助Spring的@Autowired或者javax.inject包下的@Inject註解。@Autowired可以用在構造引數或者被依賴bean的setter方法上,而且方法名是沒有限制的。不管兩者哪一個,spring都會嘗試滿足方法引數所宣告的依賴。
  但是如果以來的bean不存在或者我們忘了加@Component註解,spring會在建立應用上下文的時候拋異常。處理方式時為@Autowired屬性required設定false,並在程式碼中檢查其是否是null。
  重申:Spring專有的@Component、@Autowired註解,大多數情況下都可以被javax.inject包下的@Named和@Inject代替。