第二章 裝配Bean

完整代碼請見:https://github.com/codercuixi...
建立應用對象之間協做關係的行爲一般稱爲裝配(wiring),這也是依賴注入(DI)的本質。java

2.1 Sprig配置的可選方案

在xml文件中顯式配置(基本上公司中都不用了)
在Java中進行顯式配置
隱式的bean發現機制和自動裝配
建議:儘量使用自動配置的機制,顯式配置越少越好。
當你必需要顯式配置bean的時候(好比源碼不是由你來維護的,而你須要這些代碼配置bean的時候),使用類型安全而且比xml更爲強大的JavaConfig。
也就是本身寫的儘可能使用自動配置,他人的(第三方)使用JavaConfiggit

2.2 自動化配置Bean

主要經過兩個角度來實現自動化配置
組件掃描(component scanning):Spring會自動發現應用上下文所建立的Bean
自動裝配(autowiring):Spring會自動知足bean之間的依賴github

2.2.1 建立可被發現的Bean

總共分爲三步:
第一步,將要使用的Bean添加上@Component註解spring

package stereo_autoconfig.soundsystem;

import org.springframework.stereotype.Component;

/**
 * Create by cuixin on 2018/8/26
 **/
@Component
public class SgtPeppers implements CompactDisc {
    private String title = "Sgt.Peppers's Lonely Hearts Club Band";
    private String artist = "The Beatles";
    @Override
    public void play() {
        System.out.println("Play "+title+" by "+ artist);
    }
}

第二步,經過@ComponentScan註解來掃描指定包及其子包中帶有@Component註解的類數組

package stereo_autoconfig.soundsystem;

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

/**
 * Create by cuixin on 2018/8/26
 * 經過@ComponentScan註解啓動組件掃描,
 * 默認掃描所在包及其子包中帶有@Component註解的類
 **/
@Configuration
@ComponentScan
public class CDPlayerConfig {
}

第三步,經過@ContextConfiguration配置上下文信息,也就是聲明第二步中使用配置類安全

package stereo_autoconfig.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.assertNotNull;

/**
 * Create by cuixin on 2018/8/26
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
    @Autowired
    private CompactDisc cd;

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

}

2.2.2 爲組件掃描的bean命名

默認bean的id是將類名的第一個字母小寫,好比上面的bean的ID就是sgtPeppers.
若是想要指定不一樣的ID,只需將值傳給@Component註解。session

@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
    ...
}

2.2.3 設置組件掃描的基礎包

方法一:基於String類型指定基礎包.

Spring實戰中說這種方式是類型不安全的,我使用IDEA重命名包時,只有在Refactor時選擇Rename Package纔會更改@ComponentScan中的String值,因此才說這是不安全的。
@ComponentScan默認的掃描的是所在包及其子包,若是你掃描其餘包,或者想掃描多個包,應該怎麼設置呢?指定不一樣的基礎包ide

@Configuration //方式一,指定一個,經過設置value屬性
@ComponentScan("stereo_autoconfig.soundsystem")
public class CDPlayerConfig {
}
@Configuration //方式二,指定一個,經過設置basePackages屬性
@ComponentScan(basePackages = "stereo_autoconfig.soundsystem")
public class CDPlayerConfig {
}
@Configuration//方式三,指定多個,經過設置basePackages爲數組
@ComponentScan(basePackages = {"stereo_autoconfig.soundsystem", "stereo_autoconfig.video"})
public class CDPlayerConfig {
}

方法二:基於包中所含的類或接口來指定基礎包

@Configuration 
@ComponentScan(basePackageClasses = {CompactDisc.class, Video.class})
public class CDPlayerConfig {
}

固然爲了重構時刪除接口及相關類,你能夠在包下面建立一個空標記接口(Marker Interface),專門用來指定基礎包。ui

public Interface SoundSystemMarkerInface{
}
@Configuration 
@ComponentScan(basePackageClasses = {SoundSystemMarkerInface.class, Video.class})
public class CDPlayerConfig {
}

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

經過@ComponentScan,咱們已經能夠掃描獲得Bean,可是如何裝配這個Bean依賴的另外一個bean呢?這就是自動裝配解決的問題了。
簡單來講,自動裝配就是讓Spring自動知足bean依賴的一種方法。this

@Component
public class CDPlayer implements MediaPlayer {
    private CompactDisc cd;
    @Autowired
    public CDPlayer(CompactDisc cd){
        this.cd = cd;
        System.out.println("構造器 自動裝配");
    }

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

    @Autowired
    public void setCompactDisc(CompactDisc cd){
        this.cd = cd;
        System.out.println("Setter方法 自動裝配");
    }
    @Autowired(required = false)
    public void insertDisc(CompactDisc cd){
        this.cd = cd;
        System.out.println("其餘方法 自動裝配");
    }

}
package stereo_autoconfig.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.assertNotNull;

/**
 * Create by cuixin on 2018/8/26
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
    @Autowired
    private CompactDisc cd;
    @Autowired
    private MediaPlayer player;

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

    @Test
    public void play(){
        player.play();
    }
}

不論是構造器,Setter方法仍是其餘的方法,Spring都會去嘗試知足方法參數上所聲明的依賴。上面依次會先執行構造器方法,
而後按照出現代碼順序執行其餘自動注入方法。因此上面的輸出是
構造器 自動裝配
Setter方法 自動裝配
其餘方法 自動裝配

使用@AutoWired進行自動裝配的時候,須要注意一下幾點。

第一點,假若有且只有一個bean匹配依賴需求的話,那麼這個bean就會被裝配進來。
第二點,若是沒有匹配的bean,那麼在應用上下文建立的時候spring會拋出一個異常。
爲了不異常的出現,能夠將@AutoWired的required屬性設置爲false。但這可能致使這個bean處於未轉配狀態,使用的使用須要判斷是否爲空。
第三點,若是出現多個bean知足依賴關係的話,spring的@AutoWired自動裝配也會拋出異常,由於他們不知道選哪個

2.3 經過Java代碼裝配bean

當使用第三方庫中的組件裝配到你的應用中,在這種狀況下,是沒有辦法在它的類上添加@ComponentScan和@AutoWired註解的,所以就不能使用自動化裝配方案了。

JavaConfig比xml的優點:更爲強大,類型安全,而且對重構友好。
儘管不是必須的,但一般會將JavaConfig放到單獨的包中,使他與其餘的應用程序邏輯分離開來。
步驟:使用@Configuration建立配置類,並使用帶有@Bean的方法聲明bean,最後經過@ContextConfiguration來建立上下文

package stereo_javaconfig.soundsystem;

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

/**
 * Create by cuixin on 2018/8/26
 **/
@Configuration //建立配置類
public class CDPlayerConfig {
    @Bean //經過bean註解來聲明簡單的bean
    public CompactDisc compactDisc(){
        return new SgtPeppers();
    }
    @Bean(name = "cdPlayer") //bean id默認使用的方法名,使用方法參數實現注入,最優方法,能夠將CompactDisc放在其餘配置類中
    public CDPlayer cdPlayer(CompactDisc compactDisc){
        return new CDPlayer(compactDisc);
    }
//    @Bean(name = "cdPlayer2")
//    //bean id默認使用的方法名,引用建立bean的方法實現注入,spring會攔截全部compactDisc()調用,
//    // 確保按照規定(single,request,session)使用正確的bean,而不是簡單地每次調用都生成一個
//    public CDPlayer cdPlayer2(){
//        return new CDPlayer(compactDisc());
//    }

}
package stereo_javaconfig.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 stereo_javaconfig.soundsystem.*;

import static org.junit.Assert.*;

/**
 * Create by cuixin on 2018/8/26
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayeTest {
    @Autowired
    private MediaPlayer player;
    @Test
    public void player(){
        player.play();
    }
}

2.4 經過xml裝配Bean(略)

只是維護早先代碼的時候你纔會用到這個。

相關文章
相關標籤/搜索