手把手教你使用 Spring IOC 容器完成注入操作(xml注入 + 註解注入)

本文的代碼過多,但是每個點我會儘可能的寫的很詳細

一、爲什麼要使用 Spring?

1.1 傳統的 MVC 架構的程序

我們平時編寫一個小項目的時候,一般會採用 MVC 三層架構來編寫一個項目

  • M —— modal 模型層(實體類)
  • V —— views 視圖層 (界面)
  • C —— controller 控制層 (用來完執行一些操作)

這三層架構各自分工,獨自完成相對應的功能,但是這樣的程序寫出來會導致程序之間耦合性過高

1.2 程序耦合性過高?

耦合性過高實際上說的是程序之間的依賴性過高,解耦說的就是降低程序之間的依賴關係

我們使用 Java 通常都是寫好一個類,構造方法,setter 和 getter 等等,我們在其他的類中使用該類就得 創建一個 該類的對象,然後通過對象調用該類的各種方法。這樣整個程序之間就會產生多個類,對應的也會產生多個對象互相進行調用,因此我們整體的程序就會體現出耦合性過高的特點。

1.3 如何解耦?

  1. 我們在 Java SE 中學習過 JDBC,也學習過 properties 對象, 我們可以把 jdbc 的一些配置寫進文件中。
  2. 我們傳統一般都是創建對象,我們可以換一種方式,通過 Java 的反射機制獲取類的信息,並且創建對象
  3. 讀取 xml 文件

1.4 Spring IOC 的依賴注入

Spring 框架正式爲了解決這樣的情況出現了,它提供了 讀取 xml配置,以及註解 兩種方式實現 bean 的自動注入,而被注入的容器叫做 IOC 容器

    依賴注入:
        Dependency Injection
    IOC 的作用:
        降低程序鍵的耦合(依賴關係)
    依賴關係的管理:
       以後都交給 spring 來維護
       在當前類需要用到其他類的對象,由Spring來爲我們提供,我們只需要在配置文件中說明
       
     依賴關係的維護:
            就稱爲依賴注入
     依賴注入:
            能注入的數據,有三類
                基本類型和 string
                其他 bean 類型(在配置文件中或者註解配置過的 bean—)
                複雜類型、集合類型
            
            注入的方式:有三種
                第一種:使用構造函數提供
                第二種:使用 set方法提供
                第三種:使用註解提供

二、Spring IOC 的依賴注入(使用 xml 完成注入)

2.1 使用構造函數完成依賴注入

2.1.1 標籤的使用講解

  • 使用的標籤:constructor-arg
  • 標籤出現的位置:bean標籤的內部
  • 標籤中的屬性
    1. type:用於指定要注入的數據的數據類型,該數據類型可以是構造函數中某個或某些參數的類型
    2. index: 用於指定要注入的數據給構造函數中指定索引位置的參數賦值,索引的位置也是從 0 開始
    3. name:用於指定構造函數中指定名稱的參數賦值
    以上三個標籤用於指定給構造函數中哪個參數賦值
    5. value: 用於給基本類型和 String類型的數據
    6. ref:用於指定其它的 bean 類型數據,它指的就是 spring IOC 核心容器中出現過的 bean 對象

2.1.2 構造函數依賴注入的優缺點

  • 優勢:
    在獲取 bean 對象時,注入數據是必須的操作,否則對象無法創建成功
  • 弊端:
    改變了bean 對象的實例化方式,使我們在創建對象時,如果用不到,也必須創建

2.1.3 使用構造函數完成依賴注入的實例

注意:後面的修改全部都是基於此類的修改在這裏插入代碼片

  1. 編寫 bean.xml 配置文件
  2. 編寫一個 AccountService 接口,後面的三種方法都要實現該接口
  3. 編寫 AccountServiceImpl 實現該接口,並且記住該類的名稱和位置
  4. 編寫一個 Client 類,用來測試該接口中的方法

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

    <!-- 使用構造函數注入
         使用的標籤:constructor-arg
         標籤出現的位置:bean標籤的內部
         標籤中的屬性
            type:用於指定要注入的數據的數據類型,該數據類型可以是構造函數中某個或某些參數的類型
            index: 用於指定要注入的數據給構造函數中指定索引位置的參數賦值,索引的位置也是從 0 開始
            name:用於指定構造函數中指定名稱的參數賦值
            ============== 以上三個用於指定給構造函數中哪個參數賦值 ============
            value: 用於給基本類型和 String類型的數據
            ref:用於指定其它的 bean 類型數據,它指的就是 spring IOC 核心容器中出現過的 bean 對象

            優勢:
                在獲取 bean 對象時,注入數據是必須的操作,否則對象無法創建成功
            弊端:
                改變了bean 對象的實例化方式,使我們在創建對象時,如果用不到,也必須創建
      -->
    <bean id="accountService" class="com.itheima.service.impl.IAccountServceImpl">
        <constructor-arg name="name" value="text"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="birthday"  ref="now"></constructor-arg>
    </bean>

    <!-- 配置一個日期對象,上面會引用到 now   -->
    <bean id="now" class="java.util.Date"></bean>
</beans>

IAccountService 接口編寫

package com.itheima.service;

public interface IAccountService {
    void saveAccount();
}

IAccountServceImpl 接口實現類的編寫

package com.itheima.service.impl;

import com.itheima.service.IAccountService;
import java.util.Date;

/**
 * 賬戶業務層的實現類
 * 構造函數的注入
 * */
public class IAccountServceImpl implements IAccountService {
    // 經常變化的數據,並不適用於注入的方式
    private  String name;
    private  Integer age;
    private Date birthday;

    // 創建有參的構造方法,這個方法必須存在, 在xml中,數據就是通過有參的構造方法擦混入的
    public IAccountServceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public  IAccountServceImpl() {
        System.out.println("對象創建了");
    }

    public void saveAccount() {
        System.out.println("service 中的 saveAccount 方法執行了"+this.name + " "+ this.age + " " + this.birthday);
    }

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

Client 類的編寫

package com.itheima.client;

import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 模擬一個表現層,用於調用業務層
 * */
public class Client {

    public static void main(String[] args) {
        // 使用 mvc 三層架構,編寫 (耦合性過高)
        // IAccountService as = new IAccountServceImpl(); 
		
		// =============== 劃重點 ===============
        // 1. 獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//        ApplicationContext ac = new FileSystemXmlApplicationContext("xxx"); // 這裏填寫配置文件,在你本機上的物理地址,很少用戶
        
        // 2. 根據 id 獲取 Bean 對象 (方式一)
        IAccountService as = (IAccountService) ac.getBean("accountService");
		System.out.println(as);
        as.saveAccount();
		
		//2. 根據 id 獲取 Bean 對象 (方式二)
//        IAccountDao adao = ac.getBean("accountDao", IAccountDao.class);
//        as.saveAccount();
//        System.out.println(adao);
    }
}

運行結果:
我們沒有使用 傳統的方式,接用 Spring 框架完成了 bean 的實例化
在這裏插入圖片描述

2.2 使用 setter 完成注入

2.2.1 使用 setter 完成依賴注入的功能

    涉及的標籤:property
    出現的位置:bean 標籤的內部
    標籤的屬性:
    name:用於指定注入時所用的 set 方法名稱
    
    == 以上三個用於指定給構造函數中哪個參數賦值 ==
    
    value: 用於給基本類型和 String類型的數據
    ref:用於指定其它的 bean 類型數據,它指的就是 spring IOC 核心容器中出現過的 bean 對象

2.2.2 基於 setter 完成依賴注入的分析

  • 優勢:
    創建對象時沒有明確的限制,可以直接使用默認構造函數
  • 弊端:
    如果某個成員必須有值,則獲取對象可能 set 方法沒有執行

有了前面的內容做鋪墊,接下來做 setter 注入就會輕鬆很多,我們需要做如下步驟

  1. 在 bean.xml 添加依賴
    <!-- setter 方法注入
        涉及的標籤:property
        出現的位置:bean 標籤的內部
        標籤的屬性:
        name:用於指定注入時所用的 set 方法名稱

        ============== 以上三個用於指定給構造函數中哪個參數賦值 ============
        value: 用於給基本類型和 String類型的數據
        ref:用於指定其它的 bean 類型數據,它指的就是 spring IOC 核心容器中出現過的 bean 對象
        優勢:
            創建對象時沒有明確的限制,可以直接使用默認構造函數
        弊端:
            如果某個成員必須有值,則獲取對象可能 set 方法沒有執行
     -->

    <bean class="com.itheima.service.impl.IAccountServiceImpl2" id="accountService2">
        <property name="name" value="小紅"></property>
        <property name="age" value="19"></property>
        <property name="birthday" value="2000/4/12"></property>
    </bean>
  1. 編寫 IAccountServiceImpl2
package com.itheima.service.impl;

import com.itheima.service.IAccountService;

import java.util.Date;

/**
 * setter 注入
 * */
public class IAccountServiceImpl2 implements IAccountService {
    private String name;
    private Integer age;
    private Date birthday;

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

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

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

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

    public void saveAccount() {
        System.out.println("service 中的 saveAccount 方法執行了");
    }
}

  1. Client 內容修改
package com.itheima.client;

import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 模擬一個表現層,用於調用業務層
 * */
public class Client {

    public static void main(String[] args) {
        // 1. 獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        // 2. 根據 id 獲取 Bean 對象 (兩種方式)
        IAccountService as = (IAccountService) ac.getBean("accountService2");
        System.out.println(as);
        as.saveAccount();

    }
}
  1. 效果圖(數據成功通過 setter 注入)
    在這裏插入圖片描述

2.3 複雜數據類型注入

2.3.1 集合數據類型注入使用場景

複雜類型的注入,集合類型的注入
    常用 list 和 map
    用於給 List 結構集合注入的標籤
        list array set
    用於給 Map 結構集合注入的標籤
        map props
    結構相同,標籤可以互換

2.3.2 集合類型的數據注入

  1. bean.xml 的配置
    <!--
    複雜類型的注入,集合類型的注入
        常用 list 和 map
        用於給 List 結構集合注入的標籤
            list array set
        用於給 Map 結構集合注入的標籤
            map props
        結構相同,標籤可以互換

            IOC 內容結束
    -->
    <bean id="accountService3" class="com.itheima.service.impl.IAccountServiceImpl3">
    	<!-- 字符串注入 -->
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>
		
		<!-- 集合 List 的注入 -->
        <property name="myList">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>
		
		<!-- 集合 Set 注入--> 
        <property name="mySet">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>
		
		<!-- Map 注入 -->
        <property name="myMap">
            <map>
                <entry key="testA" value="aaa"></entry>
                <entry key="testB">
                    <value>BBB</value>
                </entry>
            </map>
        </property>
		
		<!-- Properties 注入-->
        <property name="myPros">
            <props>
                <prop key="testC">CCC</prop>
                <prop key="testD">DDD</prop>
            </props>
        </property>
    </bean>
  1. IAccountServiceImpl3 編寫
package com.itheima.service.impl;

import com.itheima.service.IAccountService;

import java.util.*;

public class IAccountServiceImpl3 implements IAccountService {
    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myPros;

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

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

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

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

    public void setMyPros(Properties myPros) {
        this.myPros = myPros;
    }

    public void saveAccount() {
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(mySet);
        System.out.println(myMap);
        System.out.println(myPros);
    }

    @Override
    public String toString() {
        return "IAccountServiceImpl3{" +
                "myStrs=" + Arrays.toString(myStrs) +
                ", myList=" + myList +
                ", mySet=" + mySet +
                ", myMap=" + myMap +
                ", myPros=" + myPros +
                '}';
    }
}
  1. Client 編寫
package com.itheima.client;

import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {

    public static void main(String[] args) {
        // 1. 獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        // 2. 根據 id 獲取 Bean 對象 (兩種方式)
        IAccountService as = (IAccountService) ac.getBean("accountService3");
        
        System.out.println(as);
        as.saveAccount();
    }
}

  1. 效果圖
    在這裏插入圖片描述

三、使用註解完成 Spring 的 IOC 注入

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
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
           
        <!--  使用註解來實現注入  -->

        <!--  告知 spring 在創建容器時要掃描的包,配置所需要的標籤不是  在 beans 約束中,而是一個名爲 context
              名稱空間和約束中( 一個標籤 + 註解的方式完成 IOC 注入)-->
        <context:component-scan base-package="com.itheima"></context:component-scan>

</beans>

編寫 IAccountService 接口

package com.itheima.service;

public interface IAccountService {
    void saveAccount();
}

編寫 IAccountDao 接口

package com.itheima.dao;

/**
 * 賬戶持久層接口
 * */
public interface IAccountDao {
    /**
     * 模擬保存賬戶
     * */
    void saveAccount();
}

3.1 用於創建對象的註解

我們在這裏實現 IAccountService 接口 創建 IAccountServiceImpl類

3.1.1 普通方法創建對象

package com.itheima.service.impl;

/*   曾經的 xml 配置,我們要在這裏協商這麼一大段的 xml 纔可以完成注入
 *  <bean id="accountService"
 *      class="com.itheima.service.impl.IAccountServceImpl
 *      <property name="" value="" | ref =""></property>
 *     "/>
 */

import com.itheima.service.IAccountService;
import com.itheima.dao.IAccountDao;

public class IAccountServiceImpl implements IAccountService {
    //1、 採用 new 創建對象,在外面還是需要通過類來創建對象解決
    private IAccountDao accountDao = new IAccountDaoImpl();

    public IAccountServiceImpl() {
        System.out.println("對象創建了");
    }

    public void saveAccount() {
        int i =1;
        accountDao.saveAccount();
        System.out.println(i);
        i++;
    }
    @Override
    public String toString() {
        return "IAccountServiceImpl{" +
                "accountDao=" + accountDao +
                '}';
    }
}

3.1.2 Componet 註解(還有和它功能一樣的三層註解)

和它功能相同的還有

  1. Controller: 一般用在表現層
  2. Service: 一般用在業務層
  3. Respository: 一般用在持久層
	三層註解的解讀:
 * 用於創建對象的註解
 *     他們的作用就和在 XML 配置文件中編寫一個 <bean> 標籤實現的功能是一樣的
 *     @Componet
 *              作用:用於把當前類對象存入spring 容器中
 *              屬性:
 *                  value 用於指定 bean 的 id,當我們不寫時,它的默認是當前類名,(AccountService  => accountService)
 *                  我的是兩個首字母都是大寫,因此不用改 IAccountServceImpl
 *      Controller: 一般用在表現層
 *      Service: 一般用在業務層
 *      Respository: 一般用在持久層
 *      以上三個註解的作用和屬性與 Component 是一模一樣的,
 *      他們三個是 spring 框架爲我們提供明確的三層使用的註解,使我們三層對象更加清晰

他們的用法都是一樣的,如下

實現: IAccountService 接口

package com.itheima.service.impl;

import com.itheima.service.IAccountService;
import com.itheima.dao.IAccountDao;
import org.springframework.stereotype.Component;

@Component(value = "accountService") 
//@Service(value = "accountService")  // 該註解和上面的註解功能是一模一樣的,只是用來區分使用情景的,如果有兩個註解,則 value 不能省去
public class IAccountServiceImpl implements IAccountService {
	// 這裏的值爲空,等會可以看到,因爲我們只是通過 Spring 創建了對象,但是並沒有把對象注入
    private IAccountDao accountDao;
	
    public void saveAccount() {
        int i =1;
        System.out.println(i);
        i++;
    }

    @Override
    public String toString() {
        return "IAccountServiceImpl{" +
                "accountDao=" + accountDao +
                '}';
    }
}

實現:IAccountDao 接口

package com.itheima.dao.impl;

import com.itheima.dao.IAccountDao;
import org.springframework.stereotype.Repository;

/**
 * 賬戶持久層的實現類
 * */
@Repository("accountDao") // 該註解功能同 Componet ,使用在持久層
public class IAccountDaoImpl implements IAccountDao {
    /**
     * 模擬保存賬戶
     */
    public void saveAccount() {
       System.out.println("保存了賬戶");
    }

    @Override
    public String toString() {
        return "IAccountDaoImpl{}";
    }
}

創建 Client 類

package com.itheima.client;

import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * 模擬一個表現層,用於調用業務層
 * */
public class Client {
    /**
     * 獲取 spring 的 Ioc 核心容器,並根據 id 獲取對象
     * ApplicationCpmtext 的三個常用實現類
     *      ClassPathXMLApplicationContext:它可以加載類路徑下的配置文件,要求配置文件必須在類路徑下,不在的話,加載不了
     *      FileSystemXmlApplicationContext:它可以加載磁盤任意路徑下的配置文件(必須有訪問權限)
     *      AnnotationConfigApplicationContext:它是用於讀取註解解耦容器的
     *
     * 核心容器的兩個接口引發出的問題
     *   ApplicationContext:單例  採用此接口
     *      它在構建核心容器時,創建對象採用的策略是利用加載的方式,也就是說,只要一讀取完配置文件馬上就創建配置文件中的配置對象
     *   BeanFactory: 多例
     *      它在構建核心容器時:創建對象採取的策略是採用延遲加載的方式。也就是說,什麼時候根據 id 獲取對象了,什麼時候才真正的創建對象
     * */
    public static void main(String[] args) {

        // 1. 獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2. 根據 id 獲取 Bean 對象 (兩種方式)
        IAccountService as = (IAccountService) ac.getBean("accountService");
        System.out.println(as);
        as.saveAccount();
    }
}

運行結果:
(因爲我並沒有進行對象注入,所以這裏的值爲 null)
在這裏插入圖片描述

3.2 用於注入數據的註解

3.2.1 數據方式剖析

 *      他們的作用就和在 xml 配置文件中的 bean 標籤寫一個 <property>標籤的作用是一樣的
 *      Autowired:
 *          作用:自動按照類型注入。只要容器中有唯一的 bean 對象類型和要注入的變量類型匹配,就可以注入成功
 *                如果 IOC 容器中沒有任何 bean 的類型和要注入的變量類型匹配,則報錯
 *                如果 IOC 容器中有多個類型匹配時
 *          出現位置:
 *              可以是變量上,也可以是方法上
 *          細節:
 *              在使用註解注入時,set 方法就不是必須的了。
 *       Qualifier:
 *             作用:在按照類中注入的基礎之上再按照名稱注入,它在給類成員注入時不能單獨使用,但是再給方法參數注入時可以使用
 *             屬性:
 *                  value: 用於指定注入的 bean 的 id
 *             補充:必須和 Autowired 一起使用
 *       Resource
 *              作用:直接按照 Bean 的id 注入,它可以獨立使用 (一個搞定上面兩個)
 *              屬性:
 *                  name:用於指定 bean 的id

3.2.2 注入方式一(Autowired + Qualifier)

重新編寫

package com.itheima.service.impl;

/*		注入方式一
 *      Autowired:
 *          作用:自動按照類型注入。只要容器中有唯一的 bean 對象類型和要注入的變量類型匹配,就可以注入成功
 *                如果 IOC 容器中沒有任何 bean 的類型和要注入的變量類型匹配,則報錯
 *                如果 IOC 容器中有多個類型匹配時
 *          出現位置:
 *              可以是變量上,也可以是方法上
 *          細節:
 *              在使用註解注入時,set 方法就不是必須的了。
 *       Qualifier:
 *             作用:在按照類中注入的基礎之上再按照名稱注入,它在給類成員注入時不能單獨使用,但是再給方法參數注入時可以使用
 *             屬性:
 *                  value: 用於指定注入的 bean 的 id
 *             補充:必須和 Autowired 一起使用
*/

import com.itheima.service.IAccountService;
import com.itheima.dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Service(value = "accountService")  // 看 Component
public class IAccountServiceImpl implements IAccountService {

    // 2、 採用註解的方式
    @Autowired
    @Qualifier("accountDao")
    private IAccountDao accountDao;

    public void saveAccount() {
        int i =1;
//        accountDao.saveAccount();
        System.out.println(i);
        i++;
    }

    @Override
    public String toString() {
        return "IAccountServiceImpl{" +
                "accountDao=" + accountDao +
                '}';
    }
}

運行效果
在這裏插入圖片描述

3.2.3 基於 Resource 的註解

這個註解就是將我們在上面用到兩個註解替換成一個:@Resource(name = "accountDao") ,產生的結果是相同的,這裏我就不放截圖了

四、Spring IOC 注入總結

  1. 首先在配置文件中加入:<context:component-scan base-package="com.itheima"></context:component-scan>,告知 Spring,我們要使用註解,然後我們在裏面填寫:base-package 的值,告知 Spring 他要掃描的包
  2. 然後在接口的實現類中的類上添加註解(創建對象的注入):@Component(value = "accountService") 並指定其 value,(如果命名規範的話,比如我寫的是 AccountService,默認值也就是上面的 value值),即可完成創建對象的操作,如果想劃分的更細一點,可以使用如下三種註解,劃分功能
    1. @Controller: 一般用在表現層
    2. @Service: 一般用在業務層
    3. @Respository: 一般用在持久層
  3. 然後在類相對應的方法,完成數據的注入,使用兩種方法都可以
    1. @Autowired + @Qualifier(“accountDao”) 完成對象的注入
    2. @Resource(name = “accountDao”) 完成對象的注入
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章