Spring的依賴注入的方式

wmxz520發表於2020-11-19

Spring依賴注入的方式

建構函式注入

在bean標籤的內部使用constructor-arg標籤就可以進行建構函式注入了。
constructor-arg標籤的屬性:

  • type:用於指定要注入的資料的資料型別,該資料型別也是建構函式中某個或某些引數的型別
  • index:用於指定要注入的資料給建構函式中指定索引位置的引數賦值,索引的位置從0開始
  • name:用於給指定建構函式中指定名稱的引數賦值
  • value:用於提供基本型別和String型別的資料
  • ref:用於指定其他的bean型別資料,就是在IOC容器中出現過的bean物件
    bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountService" class="com.sks.service.imp.AccountServiceImpl">
        <constructor-arg type="java.lang.String" value="張三"/>
        <constructor-arg index="1" value="20"/>
        <constructor-arg name="birthday" ref="birthday"/>
    </bean>

    <bean id="birthday" class="java.util.Date"/>

</beans>

AccountServiceImpl 類

public class AccountServiceImpl implements AccountService {

    private String name;
    private Integer age;
    private Date birthday;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "AccountServiceImpl{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }

    public AccountServiceImpl(String name, Integer age, Date birthday) {
        System.out.println("含參的構造方法被呼叫了");
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public AccountServiceImpl() {
        System.out.println("構造方法呼叫");
    }

    @Override
    public int addMoney(int money) {
        System.out.println("向賬戶中加錢:" + money);
        return 0;
    }

    @Override
    public void saveAccount(Account account) {
        System.out.println("saveAccount方法執行了");
    }
}

測試

	/**
     * 測試建構函式注入
     */
    @Test
    public void test8() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");;

        AccountService accountService = (AccountService) applicationContext.getBean("accountService");

        System.out.println(accountService.toString());
    }

執行測試以後,可以在控制檯看到以下內容:
在這裡插入圖片描述
優點:在獲取bean物件時,注入資料是必須的操作,否則物件無法建立成功。
缺點:改變了bean物件的例項化方式,使我們在建立物件時,如果用不到這些資料也必須提供。

setter方法注入

在bean標籤內部使用property標籤進行配置。
property標籤的屬性:

  • name:用於指定注入時所呼叫的set方法名稱
  • value:用於提供基本型別和String型別的資料
  • ref:用於指定其他的bean型別資料

這裡面我們注入了基本型別、包裝型別、日期型別資料。
AccountServiceImpl 類

public class AccountServiceImpl implements AccountService {

    private String name;
    private Integer age;
    private Date birthday;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("給name設定值");
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        System.out.println("給age設定值");
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        System.out.println("給birthday設定值");
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "AccountServiceImpl{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }

    public AccountServiceImpl(String name, Integer age, Date birthday) {
        System.out.println("含參的構造方法被呼叫了");
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public AccountServiceImpl() {
        System.out.println("構造方法呼叫");
    }

    @Override
    public int addMoney(int money) {
        System.out.println("向賬戶中加錢:" + money);
        return 0;
    }

    @Override
    public void saveAccount(Account account) {
        System.out.println("saveAccount方法執行了");
    }
}

bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        
    <bean id="accountService" class="com.sks.service.imp.AccountServiceImpl">
    	<!--注入基本型別、包裝型別、日期型別資料-->
       <property name="age" value="22"/>
        <property name="name" value="李四"/>
        <property name="birthday" ref="birthday"/>
    </bean>

    <bean id="birthday" class="java.util.Date"/>
</beans>

測試

    /**
     * 測試setter方法注入
     */
    @Test
    public void test9() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");;

        AccountService accountService = (AccountService) applicationContext.getBean("accountService");

        System.out.println(accountService.toString());
    }

執行測試以後,可以在控制檯看到以下內容:
在這裡插入圖片描述
優勢:建立物件時沒有明確的限制,可以直接使用預設建構函式。
缺點:如果又某個成員必須有值,則獲取物件有可能是set方法沒有執行。

對集合型別資料進行注入

AccountService2Impl 類

public class AccountService2Impl implements AccountService2 {

    private String[] myStrs;

    private List<String> myList;

    private Set<String> mySet;

    private Map<String, String> myMap;

    private Properties myProps;

    public String[] getMyStrs() {
        return myStrs;
    }

    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    }

    public List<String> getMyList() {
        return myList;
    }

    public void setMyList(List<String> myList) {
        this.myList = myList;
    }

    public Set<String> getMySet() {
        return mySet;
    }

    public void setMySet(Set<String> mySet) {
        this.mySet = mySet;
    }

    public Map<String, String> getMyMap() {
        return myMap;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    public Properties getMyProps() {
        return myProps;
    }

    public void setMyProps(Properties myProps) {
        this.myProps = myProps;
    }


    @Override
    public String toString() {
        return "AccountService2Impl{" +
                "myStrs=" + Arrays.toString(myStrs) +
                ", myList=" + myList +
                ", mySet=" + mySet +
                ", myMap=" + myMap +
                ", myProps=" + myProps +
                '}';
    }

}

bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountService2" class="com.sks.service.imp.AccountService2Impl">
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <property name="myList">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>

        <property name="mySet">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>

        <property name="myProps">
            <props>
                <prop key="name">柯森</prop>
                <prop key="age">23</prop>
            </props>
        </property>
        
        <property name="myMap">
            <map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
                <entry key="key3">
                    <value>value3</value>
                </entry>
            </map>
        </property>  
    </bean>
    
</beans>

測試

    /**
     * 測試注入複雜型別/集合資料
     */
    @Test
    public void test10() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");

        AccountService2 accountService2 = (AccountService2) applicationContext.getBean("accountService2");

        System.out.println(accountService2.toString());
    }

執行測試以後,可以看到在控制檯列印輸出了以下內容:
在這裡插入圖片描述
這說明我們注入集合型別資料成功了。

註解注入

用於注入資料的註解

註解作用
@Autowired按照型別注入,如果又多個型別相同的再按名稱
@Qualifier在按照類中注入的基礎之上再按照名稱注入;屬性:value,用於指定注入bean的id
@Resource直接按照bean的id注入,可以獨立使用
@Value注入基本型別的資料,不能注入集合

bean.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
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--建立bean時要掃描的包-->
    <context:component-scan base-package="com.sks"/>

</beans>

AccountService4Impl 類

@Component
public class AccountService4Impl implements AccountService3 {


    @Autowired
    private AccountDao accountDao;

    @Override
    public void addMoney(int money) {
        System.out.println("向賬戶中加錢....AccountService3Impl");
    }
}

假設此時只有一個AccountDao的實現類,並且這個類也加上了@Repository註解,那麼我們這樣注入是可以成功的,但是如果容器中存在多個AccountDao的實現類,此時僅僅使用AccountDao是不能完成資料注入的,需要配合@Qualifier註解使用注入資料。

假設現有如下兩個實現類,那我們應該怎麼寫才能成功注入資料?
在這裡插入圖片描述
在這裡插入圖片描述

@Component
public class AccountService4Impl implements AccountService3 {
	
	//錯誤寫法,預設會去容器中查詢名稱為accountDao的bean
	 //@Autowired
   	//private AccountDao accountDao;

	
	//正確寫法
	//@Autowired
	//private AccountDao accountDao1
	
	//正確寫法
	//@Autowired
	//private AccountDao accountDao1;
	
	//正確寫法
    @Autowired
    @Qualifier("accountDao1")
    private AccountDao accountDao;

    @Override
    public void addMoney(int money) {
        System.out.println("向賬戶中加錢....AccountService3Impl");
    }

}

測試

    @Test
    public void test2() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");
        AccountService4Impl accountService4 = (AccountService4Impl) applicationContext.getBean("accountService4Impl");

        System.out.println("accountService4:" + accountService4);
    }

@Value註解的基本使用
在使用@Value注入基本型別和String型別的資料時使用"#“號;使用@Value讀取配置檔案的值時需要使用”$"符號,同時使用@PropertySource註解指定配置檔案的位置。

@Component
@PropertySource("classpath:db.properties")
public class AccountService4Impl implements AccountService3 {

    @Autowired
    @Qualifier("accountDao1")
    private AccountDao accountDao;
	
	//使用SPEL表示式只注入值
    @Value("#{19 - 9}")
    private int age;

    @Value("zhangsan")
    private String name;
	
	//讀取作業系統的名稱
    @Value("#{systemProperties['os.name']}")
    private String osname;

    //讀取資料庫配置檔案中的值
    @Value("${password}")
    private String password;


    @Override
    public void addMoney(int money) {
        System.out.println("向賬戶中加錢....AccountService3Impl");
    }

}

測試

    @Test
    public void test2() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");
        AccountService4Impl accountService4 = (AccountService4Impl) applicationContext.getBean("accountService4Impl");

        System.out.println("accountService4:" + accountService4 + " " + accountService4.getName() + " " + accountService4.getAge());

    }

斷點除錯可以看到如下結果,說明我們使用@Value注入資料成功。
在這裡插入圖片描述

相關文章