1. 程式人生 > >自動化裝配Bean

自動化裝配Bean

text 不能 xml配置 自動 可能 spring註解 避免 this keyword

一、Spring裝配-自動化裝配

@Component和@ComponentScan

通過spring註解(@Component)來表明該類會作為組件類,並告知Spring要為這類創建bean,不過組件掃描默認是不啟動的,需要顯式的配置Spring,從而命令Spring去尋找帶有(@Component)註解的類,並為其創建bean。

1、定義接口

package com.seven.springTest.service;

public interface HelloWorldApi {
    public void sayHello();
}

2、定義接口的實現類

package com.seven.springTest.service.impl;

import org.springframework.stereotype.Component;

import com.seven.springTest.service.HelloWorldApi;

@Component    //通過註解指定該類組件類,告知spring要為它創建Bean
public class PersonHelloWorld implements HelloWorldApi {

    @Override
    public void sayHello() {
        System.out.println("Hello World,This Is Person!");
    }
}

3、前面說過了,spring並不能自動啟用組件掃描,需要進行顯式的配置,這裏通過java類來進行顯式的配置,定義java配置類HelloWorldConfig,在配置類中我們沒有顯式的聲明任何bean,只不過是使用了@CompontentScan註解來啟用組件掃描

package com.seven.springTest;

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

@Configuration
@ComponentScan   // 啟用組件掃描
public class HelloWorldConfig {

}

現在所有的工作已經完成,我們來測試下

package com.seven.springTest.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.seven.springTest.HelloWorldConfig;
import com.seven.springTest.service.HelloWorldApi;

public class HelloWorldTest {

    public static void main(String[] args) {
        //1. 聲明Spring上下文,采用java配置類
        ApplicationContext ac = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
        //2. 聲明Spring應用上下文,采用xml配置
        //ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        //通過Spring上下文獲取Bean,在這裏Spring通過自動掃描發現了PersonHelloWorld的實現,並自動創建bean。
        HelloWorldApi hwapi = ac.getBean(HelloWorldApi.class);
        //通過sayHello()的輸入內容可以看到,hwapi為PersonHelloWorld的實例
        hwapi.sayHello();
    }
}

通過上的代碼,在控制臺會輸出下面的內容 “Hello World,This Is Person!”

Spring容器通過組件掃描發現了PersonHelloWorld類,並為它創建了對應的bean。到此為止,我們通過簡單的註解實現自動化裝配,在上面的案例中,HelloWorldConfig配置類@ComponentSan如果沒有其他配置,只會掃描HelloWorldConfig所在包或者它的子包,如果需要制定掃描的包,可以通過

@ComponentScan("com.seven.springTest")

或者

@ComponentScan(basePackages="com.seven.springTest")

basePackages允許設置多個包,,只需要把basePackages熟悉設置成一個數組即可

@ComponentScan(basePackages={"com.seven.springTest.service","com.seven.springTest.impl"})

除了通過java配置類來設置Spring啟用組件掃描,還可能通過xml類顯式配置,參考下面xml配置,並在獲取Spring應用上下文時通過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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    
    <!-- 啟用Spring組件掃描-->
    <context:component-scan base-package="com.seven.springTest"></context:component-scan>
    
</beans>

在上面的案例中,我們通過@Component和@ComponentScan來隱式的配置完成了Bean的裝配工作,接下來我們深入的探討下@Component和@ComponentScan

Spring容器在管理Bean的時候,會給每一個Bean有一個ID標識,上面的例子,如果HelloWorldApi的實現類有多個,那麽Spring容器該怎麽分配Bean呢,如果我們在使用@Component的時候,沒有明確的給PersonHelloWorld設置一個ID,Spring容器會默認給bean給定一個ID,一般為類名(第一個字母會變為小寫,例如跑personHelloWorld),所以下面的代碼也是成立的

//通過bean的ID來獲取實例
HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("personHelloWorld");
hwapi.sayHello();

同時我們也可以為bean設置ID,如下:

@Component("person")    //為bean設置ID為“person”
public class PersonHelloWorld implements HelloWorldApi {

    @Override
    public void sayHello() {
        // TODO Auto-generated method stub
        System.out.println("Hello World,This Is Person!");
    }

}

這樣我們在獲取bean的時候就可通過ID來獲取,如下:

// 根據設置的bean ID來獲取bean
HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("person");

在以上的案例中我們使用了@Component和@ComponentScan實現了組件掃描,目前為止我們都是對單一的對象進行操作,如果程序復雜點,對象之間存在依賴,該如何處理呢?下面我們就來研究下如何為bean添加註解實現自動裝配

@AutoWired

在上面的案例中Person對整個世界說了一句Hello,可說話只有旁邊的人知道,我們需要讓更多的聽到我們的“hello world”,我們就需要一些工具,我們使用電視來廣播就能讓更多的人聽到了,首先我們定義一個傳播工具接口

package com.seven.springTest.service;

public interface TransmittingTool {
    void work(String message);
}

接下來我們來創建我們的TV

package com.seven.springTest.service.impl;
import org.springframework.stereotype.Component;

import com.seven.springTest.service.TransmittingTool;

@Component   //設置為需要被掃描到的組件
public class TVTool implements TransmittingTool {

    @Override
    public void work(String message) {
        //傳播工具工作,把我們的消息傳播出去
        System.out.println(message);
    }
}

接下來我們需要對我們之前的PersonHelloWorld的sayHello()方法進行一些修改,讓它可以通過傳播工具來對全世界說Hello

package com.seven.springTest.service.impl;

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

import com.seven.springTest.service.HelloWorldApi;
import com.seven.springTest.service.TransmittingTool;

@Component
public class PersonHelloWorld implements HelloWorldApi {
    //定義傳播工具
    @Autowired   //1.直接變量添加註解
    private TransmittingTool transmittingTool;

//  @Autowired   //2. 通過構造函數註入依賴
//  public PersonHelloWorld(TransmittingTool transmittingTool) {
//      this.transmittingTool = transmittingTool;
//  }
    
//  @Autowired    //3. 通過屬性的Setter方法註入依賴
//  public void setTransmittingTool(TransmittingTool transmittingTool) {
//      this.transmittingTool = transmittingTool;
//  }

//  @Autowired  //4. 通過其他函數註入依賴
//  public void inserttool(TransmittingTool transmittingTool){
//      this.transmittingTool=transmittingTool;
//  }
    
    @Override
    public void sayHello() {

        // 通過傳播工具來sayHello
        transmittingTool.work("Hello World,This Is Person!--form TV");
    }
}

首先我們定義了一個傳播工具,這個工具的具體實現我們不清楚,需要Spring容器去給我註入依賴。
@Autowired直接可以使用在類變量、構造函數、Setter和其他任何方法上,參考代碼中1-4的實現

  1. 直接在變量上添加註解
  2. 在構造函數上添加註解,在spring容器通過構造器實例化bean的時候,會傳入一個提供給transmittingTool的實例,註入依賴;
  3. 通過Setter方法或者其他函數,Spring在初始化bean以後,會盡量的去滿足bean的所有依賴,如果使用第4個種註入,我們在HelloWorldTest中重來沒有調用過inserttool()方法,可是sayHello()還是能正常執行,Spring會去根據@Autowired來盡量嘗試去註入PersonHelloWorld的依賴。

如果能夠配置到1個滿足要求的依賴,那麽這個被依賴的bean就會被裝配進來,如果沒有匹配的依賴bean,那麽應用上下文創建的時候,Spring會拋出一個異常,為了避免異常,我們可以把@Autowired的required設置為false;

@Autowired(required=false)   //2. 通過構造函數註入依賴
public PersonHelloWorld(TransmittingTool transmittingTool) {
    this.transmittingTool = transmittingTool;
}
    

@Autowired的required設置給false後,Spring為嘗試給bean自動裝配,註入依賴,如果沒有匹配的bean的話,Spring將會讓這個bean處於未裝配的狀態,當時把required設置為false的時需要註意,因為這個依賴bean處於未裝配狀態,在調用依賴的時候,如果你的代碼做null的檢查,這個處於未裝配狀態的屬性有可能會發生異常。

如果有多個bean能滿足依賴關系的話,Spring也會拋出異常,表明沒有明確指出選擇哪個bean進行自動裝配。這個在後面我會單獨開一篇講解Spring的高級裝配,到時候在詳細說明,大家可以關註後續的文章。

自動化裝配Bean