spring 裝配bean(二)


1. 創建應用對象之間協作關係的行爲通常程序裝配,這也是依賴注入的本質
2. spring裝配bean的三種機制 , 通常顯示的配置越少越好,當必須顯示配置bean的時候,推薦使用比xml更加強大的javaConfig,只有當你想使用便利的xml命名空間的時候,才應該使用xml
①:通過xml中進行顯示配置
②:在java中進行顯示的配置
③:隱式的bean發現機制和自動裝配
3. 自動化裝配bean :spring從2個角度來實現自動化裝配,組件掃描和自動裝配組合在一起,能夠將顯示配置降到最低
①組件掃描(component scanning) spring會自動發現應用上下文中所創建的bean
②:自動裝配(autowiring):spring會自動滿足bean之間的依賴
③:創建可被發現的bean示例

--接口
package package2;
public interface CompactDis {
    void play();
}

--實現類
package package2;
import org.springframework.stereotype.Component;
//註明是組件類 告知spring要爲這個類創建bean
//組件掃描默認是不啓用的,所以需要顯示配製一下spring,命令它去尋找帶有@Component註解的類,併爲其創建bean
@Component
public class Sgtprppers implements CompactDis{
    private String title="這是標題";
    private String artist="The Beatles";
    @Override
    public void play() {
        System.out.println(title+"==="+artist);
    }
}

--java版啓動自動掃描
package package2;
import org.springframework.context.annotation.ComponentScan;
//@ComponentScan java配置啓用組件掃描的方式
//如果沒有其他配置的話,默認掃描的是與配置類相同的包及子包下帶有@Component的註解類,自動爲其創建bean
Configuration
@ComponentScan
public class CDPlayerConfig {
}

--xml版本啓用自動掃描
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="package2"/>
</beans>

--test
//使用了springJunit4ClassRunner,測試開始的時候自動創建spring應用上下文
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration 需要在哪加載配置java版本  @ContextConfiguration(classes=CDPlayerConfig.class)
//@ContextConfiguration("classpath:spring.xml")  xml版本
@ContextConfiguration(classes = CDPlayerConfig.class)
public class TestCd {

    @Autowired
    private CompactDis compactDis;

    @Test
    public void test() {
        Assert.notNull(compactDis);
    }
}

  1. 爲組件掃面的bean命名,sping應用上下文中的所有的bean都會給一個id,當沒有明確表明的時候,sping默認會把類名首字母小寫當做id
//爲bean命名
@Component("指定的名稱")
@Named("指定的名稱")//java依賴注入規範中所提供
  1. 設置組件掃面的基礎包
@ComponentScan("需要掃描的包名")
//如果想要更加清晰的表明所設置的是基礎包,可以通過basePackages屬性進行配置,這裏設置的基礎包是String類型的,如果包名改變就會出現錯誤
@ComponentScan(basePackages="需要掃描的包名")
@ComponentScan(basePackages={"掃描包1","掃描包2"})

//可以通過設置包中所包含的類,這些類所所在的包將會作爲組件掃描的基礎包
@ComponentScan(basePackageClasses={配置類1.class,配置類2.class})

  • 通過爲bean添加註解實現自動裝配
package package2;

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

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

     //當Autowired註解添加到構造方法的時候,表明當Spring創建CDPlayer bean的時候 會通過這個構造器進行實例化
     // 並且會傳入一個可設置給CompactDisc類型的bean
    //@Autowired 和Inject(來源Java依賴注入規範)效果類似
     @Autowired
    public CDPlayer(CompactDisc cd) {
        this.cd = cd;
    }

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

    //Autowired註解不進可以用在構造器上,還能用在屬性的Setter方法上
    //不管是構造器、Setter方法 還是其它方法,Spring都會嘗試滿足方法參數上所聲明的依賴
    //當只有一個bean匹配依賴需求的時候,這個bean會被裝配起來,沒有匹配的bean的時候會拋出異常,爲了避免異常的出現,設置屬性required=false
    //當required=false 的時候 spring會嘗試自動裝配,但是沒有匹配的bean的話,spring會讓這個bean處於未裝配狀態,如果存在多個將會拋出異常 表示沒有明確指定用哪個bean裝配
    @Autowired(required = false)
    public void setCd(CompactDisc cd) {
        this.cd = cd;
    }
}
  • 通過java代碼裝配bean
    ①:儘管在許多場景下都可以使用自動裝配,但是有的時候需要明確配置,例如 將第三方組件裝配到應用中,這時候是沒有辦法使用自動裝配的.顯示的聲明bean的時候有2中方式 java代碼和xml
    ②帶有@bean註解的方法可以採用任何必要的java功能來產生bean實例,構造器和set方法只是@Bean的2個簡單樣例
    //@Bean會告訴spring這個方法返回一個對象,該對象要註冊爲spring應用上下文中的bean
    @Bean
    public CompactDis sgtPeppers(){
        return  new sgtPeppers();
    }

    //默認情況下 bean的id與帶有@Bean註解的方法名是 一樣的 可以通過name進行重新命名
    @Bean(name="ss")
    public CompactDis sgtPeppers(){
        return  new sgtPeppers();
    }

    //這個方法並沒有使用默認的構造器創建實例,而是調用了需要傳入對象來構造實例
    //bean默認是單例的
    //這種是通過方法調用
    @Bean
    public CDPlayer cdPlayer(){
        return new CDPlayer(sgtPeppers())
    }

    //當做參數調用
    @Bean
    public CDPlayer cdPlayer(CompactDis compactDis){
        return new CDPlayer(compactDis)
    }
  • 通過xml裝配bean
      <!-- bean標籤類似於JavaConfig中@Bean註解 class是全限定的類名 -->
    <bean id="sgtprppers" class="package2.Sgtprppers"/>

    <!--當沒有指定id的時候 這個bean將會根據全限定名來進行命名"package2.Sgtprppers#1 有2個就是 package2.Sgtprppers#2
        在基於JavaConfig的配置中我們需要直接負責創建bean的實例,在xml中默認調用構造器創建不用人爲干預
     -->
    <bean  class="package2.Sgtprppers"/>

    <!--當spring遇到這個bean元素的時候,她會創建一個CDPlayer實例
     <constructor-arg ref="compactDis"/> 元素會告知spring將要一個id爲compactDis的bean引用傳遞到CDPlayer構造器中
     作爲替代方案可以使用spring的C-命名空間 必須引入標題頭  xmlns:c="http://www.springframework.org/schema/c"
    -->
    <bean id ="cdPlayer" class="package2.CDPlayer">
        <constructor-arg ref="compactDis"/>
    </bean>

    <!--使用c-命名空間和聲明構造參數
        屬性名 c:開頭 也就是命名空間的前綴 接下來就是要裝配的構造器參數名 然後-ref  最後引用的bean id 
    -->
    <bean id ="cd" class="package2.CDPlayer" c:cd-ref="compactDis"/>

    <!--優化版
        將參數嗎替換成參數的索引,防止改參數名報錯 因爲xml中不允許數字作爲屬性的第一個字符,因爲必須添加下劃線作爲前綴
        當只有一個參數的時候可以 直接寫c:_-ref
    -->
    <bean id ="cd2" class="package2.CDPlayer" c:_0-ref="compactDis"/>
  • 將字面量注入到構造器中
    private String title;
    private List<String> tracks;

<!--
   因爲是構造參數必須要聲明它  可以傳null 當調用方法的時候就會出現空指針異常
   -->
    <bean id="balkDiscList" class="package2.BalkDiscList">
        <constructor-arg value="xxx"/>
        <constructor-arg><null/></constructor-arg>
    </bean>

    <!--給List賦值  預製類似我們也可以使用<ref>元素替代<value>,實現bean引用列表的裝配
        <list>
            <red bean="xxx1"/>
            <red bean="xxx2"/>
        <list>
       set與list賦值區別不大 但是set會忽略重複的值,存放順序不能保證
    -->
    <bean id="balkDiscList1" class="package2.BalkDiscList">
        <constructor-arg value="xxx"/>
        <constructor-arg>
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </constructor-arg>
  • 設置屬性
public class CDPlayer {
    //
    private CompactDis compactDis;
    @Autowired
    public void setCompactDis(CompactDis compactDis) {
        this.compactDis = compactDis;
    }

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

 <!--在創建bean的時候不會報錯 但是調用方法的時候會報空指針異常 因爲沒有注入調用的那個屬性-->
    <bean id="cdPlayer" class="package2.CDPlayer"/>

    <!--property元素爲屬性的set方法提供與constructor-arg 元素相同的功能
        此處可以使用p標籤 引入頭 xmlns:p="http://www.springframework.org/schema/p"
        p標籤與c標籤類似
    -->
    <bean id="cdPlayer2" class="package2.CDPlayer">
        <property name="compactDis" ref="compactDis"></property>
    </bean>

    <!--
    p標籤使用規則
    p:compactDis(屬性名)-ref(注入bean引用)="所注入bean的id"
    -->
    <bean id="cdPlayer2" class="package2.CDPlayer" p:compactDis-ref="compactDis"></bean>
  • 設置屬性的字面量
public class BalkDiscList {
    private String title;
    private List<String> tracks;

    public void setTitle(String title) {
        this.title = title;
    }

    public void setTracks(List<String> tracks) {
        this.tracks = tracks;
    }


}

<!-- p標籤與c標籤一樣  沒有ref的是給字面量賦值
    我們不能使用p:標籤來裝配集合 但是我們可以使用 spring util-命名空間來簡化
    引入標籤頭        xmlns:util="http://www.springframework.org/schema/util"
    -->
    <bean id="really" class="package2.BalkDiscList">
        <property name="title" value="xxx"/>
        <property name="tracks">
            <list>
                <value>1</value>
                <value>2</value>
            </list>
        </property>
    </bean>


    <!--使用util標籤-->
    <util:list id="trackList">
        <value>1</value>
        <value>2</value>
    </util:list>
    <bean id="really" class="package2.BalkDiscList" p:title="xxx" p:tracks="trackList"/>
  • spring util-命名空間中的元素
<util:constant> 引入某個類型的public static域,並將器暴露爲bean
<util:list> 創建一個java.util.List類型的bean,其中包含值和引用
<util:map>  創建一個java.util.Map類型的bean,其中包含值和引用
<util:properties>  創建一個java.util.properties類型的bean
<util:properties-path> 引用一個bean的屬性(或內嵌屬性),並將其暴露爲bean
<util:set> 創建一個java.util.Set類型的bean,其中包含值和引用
  • 導入和混合配置
    在spring應用中,儘管可能會同時使用自動化和顯示配置,即便你更喜歡通過javaConfig實現顯示配置,但是有的時候XML確是最佳的方案
    關於混合配置,第一件事需要了解就是自動裝配時,它並不在意要裝配的bean來自哪裏
@Configuration
public class CDConfig {
    @Bean
    public CompactDis compactDis() {
        return new SgtPeppers();
    }
}

//compactDis()方法已經移除,我們需要將兩個類組合到一起
//一種是使用@Import註解導入 CDConfig
//或者採用一種更高級的方法 去創建一個更高級別的配置 同時引入這兩個配置類@Import({CDConfig.class,CDPlayerConfig.class})
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {

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

}
//當一個類配置在xml中 一個是通過javaConfig配置的時候 可以類中使用註解@ImportResource("classpath:xml文件名")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章