天天看點

11-SSM_Spring_IoC與DI

目錄

​​一,Spring介紹​​

​​1,什麼是架構​​

​​2,spring是什麼​​

​​3,Spring的優勢​​

​​4,Spring的體系結構​​

​​4.1 核心容器​​

​​4.2 資料通路/內建​​

​​4.3 Web​​

​​4.4 其他​​

​​二,Spring核心-IoC​​

​​1,概念​​

​​2,入門案例​​

​​2.1 在一個工程中建立多個項目 ​​

​​2.2 建立執行個體的方法​​

​​2.3 擷取Spring容器​​

​​2.4 其他常用的api​​

​​2.5 建立非自定義對象​​

​​4,bean标簽屬性​​

​​4.1 scope​​

​​4.2 lazy-init​​

​​4.3 init-method與destroy-method​​

​​5,建立對象的3種方式​​

​​5.1 預設的構造方法​​

​​5.2 帶參數的構造方法 ​​

​​5.3 使用工廠方法​​

​​6,基于XML的DI​​

​​6.1 通過set方法注入​​

​​6.2 通過構造方法注入​​

​​6.3 自動注入​​

​​7,基于注解實作IoC​​

​​7.1 聲明Bean的注解 @Component​​

​​7.2 包掃描​​

​​8,屬性注入的注解實作​​

​​8.1 屬性注入@Vaule​​

​​8.2 byType自動注入@Autowired​​

​​8.3 byName自動注入@Autowired和@Qualifier​​

​​8.4 自動注入@Resource​​

一,Spring介紹

1,什麼是架構

架構(Framework):框(指其限制性)架(指其支撐性),在軟體設計中指為解決一個開放性問題而設計的具有一定限制性的支撐結構。在此結構上可以根據具體問題擴充、安插更多的組成部分,進而更迅速和友善地建構完整的解決問題的方案。
  1. 架構本身一般不完整到可以解決特定問題
  2. 架構天生就是為擴充而設計的
  3. 架構裡面可以為後續擴充的元件提供很多輔助性、支撐性的友善易用的實用工具(utilities),也就是說架構時常配套了一些幫助解決某類問題的庫(libraries)或工具(tools)。

如何學習架構呢?

  • 1、知道架構能做什麼
  • 2、學習架構的文法,一般架構完成一個功能需要一定的步驟
  • 3、架構的内部實作原理(擴充)
  • 4、嘗試實作一個架構(提升)

2,spring是什麼

Spring官網 ​​Spring | Home​​

11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI

Spring 被稱為 J2EE 的春天,是一個是分層的 Java SE/EE full-stack 開源的輕量級的 Java 開發架構, 是最受歡迎的企業級 Java 應用程式開發架構,數以百萬的來自世界各地的開發人員使用 Spring 架構來建立性能好、易于測試、可重用的代碼。

Spring具有控制反轉(IoC)和面向切面(AOP)兩大核心。Java Spring架構通過聲明式方式靈活地進行事務的管理,提高開發效率和品質。

Spring 架構不僅限于伺服器端的開發。從簡單性、可測試性和松耦合的角度而言,任何 Java 應用都可以從 Spring 中受益。Spring 架構還是一個超級粘合平台,除了自己提供功能外,還提供粘合其他技術和架構的能力。

3,Spring的優勢

1、友善解耦,簡化開發

Spring 就是一個大工廠,可以将所有對象的建立和依賴關系的維護交給 Spring 管理。

2、友善內建各種優秀架構

Spring 不排斥各種優秀的開源架構,其内部提供了對各種優秀架構(如 Struts2、Hibernate、MyBatis 等)的直接支援。

3、降低 Java EE API 的使用難度

Spring 對 Java EE 開發中非常難用的一些 API(JDBC、JavaMail、遠端調用等)都提供了封裝,使這些 API 應用的難度大大降低。

4、友善程式的測試

Spring 支援 JUnit4,可以通過注解友善地測試

5、AOP 程式設計的支援

Spring 提供面向切面程式設計,可以友善地實作對程式進行權限攔截和運作監控等功能。

6、聲明式事務的支援

隻需要通過配置就可以完成對事務的管理,而無須手動程式設計。

4,Spring的體系結構

Spring 為我們提供了一站式解決方案,但Spring 是子產品化的,允許挑選和選擇适用于項目的子產品,不需要把剩餘部分也引入。

Spring 架構提供約 20 個子產品,可以根據應用程式的要求來選擇。

11-SSM_Spring_IoC與DI

4.1 核心容器

核心容器由 Spring-core,Spring-beans,Spring-context,Spring-context-support和Spring-expression(SpEL,Spring 表達式語言,Spring Expression Language)等子產品組成

  • Spring-core 子產品提供了架構的基本組成部分,包括 IoC 和依賴注入功能。
  • Spring-beans 子產品提供 BeanFactory,工廠模式的微妙實作,它移除了編碼式單例的需要,并且可以把配置和依賴從實際編碼邏輯中解耦。
  • context 子產品建立在由 core和 beans 子產品的基礎上建立起來的,它以一種類似于 JNDI 注冊的方式通路對象。Context 子產品繼承自 Bean 子產品,并且添加了國際化(比如,使用資源束)、事件傳播、資源加載和透明地建立上下文(比如,通過 Servelet 容器)等功能。Context 子產品也支援 Java EE 的功能,比如 EJB、JMX 和遠端調用等。ApplicationContext 接口是 Context 子產品的焦點。
  • Spring-context-support 提供了對第三方內建到 Spring 上下文的支援,比如緩存(EhCache,Guava, JCache)、郵件(JavaMail)、排程(CommonJ, Quartz)、模闆引擎(FreeMarker,JasperReports, Velocity)等。
  • Spring-expression 子產品提供了強大的表達式語言,用于在運作時查詢和操作對象圖。它是 JSP2.1規範中定義的統一表達式語言的擴充,支援 set 和 get 屬性值、屬性指派、方法調用、通路數組集合及索引的内容、邏輯算術運算、命名變量、通過名字從 Spring IoC 容器檢索對象,還支援清單的投影、選擇以及聚合等。

完整依賴關系

11-SSM_Spring_IoC與DI

4.2 資料通路/內建

JDBC=Java Data Base Connectivity

ORM=Object Relational Mapping

OXM=Object XML Mapping

JMS=Java Message Service

  • JDBC 子產品提供了 JDBC 抽象層,它消除了冗長的 JDBC 編碼和對資料庫供應商特定錯誤代碼的解析。
  • ORM 子產品提供了對流行的對象關系映射 API 的內建,包括 JPA、JDO 和 Hibernate 等。通過此子產品可以讓這些 ORM 架構和 Spring的其它功能整合,比如前面提及的事務管理。
  • OXM 子產品提供了對 OXM 實作的支援,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
  • JMS 子產品包含生産(produce)和消費(consume)消息的功能。從 Spring 4.1 開始,內建了Spring-messaging 子產品。
  • 事務子產品為實作特殊接口類及所有的 POJO 支援程式設計式和聲明式事務管理。

4.3 Web

  • Web 子產品提供面向 web 的基本功能和面向 web 的應用上下文,比如多部分(multipart)檔案上傳功能、使用 Servlet 監聽器初始化 IoC 容器等。它還包括 HTTP 用戶端以及 Spring 遠端調用中與web 相關的部分。
  • Web-MVC 子產品為 web 應用提供了模型視圖控制(MVC)和 REST Web服務的實作。Spring 的MVC 架構可以使領域模型代碼和 web 表單完全地分離,且可以與 Spring 架構的其它所有功能進行內建。
  • Web-Socket 子產品為 WebSocket-based 提供了支援,而且在 web 應用程式中提供了用戶端和伺服器端之間通信的兩種方式。
  • Web-Portlet 子產品提供了用于 Portlet 環境的 MVC 實作,并反映了 Spring-webmvc 子產品的功能。

4.4 其他

  • AOP 子產品提供了面向方面(切面)的程式設計實作,允許你定義方法攔截器和切入點對代碼進行幹淨地解耦,進而使實作功能的代碼徹底的解耦出來。
  • Aspects 子產品提供了與 AspectJ 的內建,這是一個功能強大且成熟的面向切面程式設計(AOP)架構。
  • Instrumentation 子產品在一定的應用伺服器中提供了類 instrumentation 的支援和類加載器的實作。
  • Messaging 子產品為 STOMP 提供了支援作為在應用程式中 WebSocket 子協定的使用。它也支援一個注解程式設計模型,它是為了選路和處理來自 WebSocket 用戶端的 STOMP 資訊。
  • 測試子產品支援對具有 JUnit 或 TestNG 架構的 Spring 元件的測試。

二,Spring核心-IoC

1,概念

Ioc—Inversion of Control,即“控制反轉”,不是什麼技術,而是一種設計思想。

IoC 是指在程式開發中,執行個體的建立不再由調用者管理,而是由 Spring 容器建立。Spring 容器會負責控制程式之間的關系,而不是由程式代碼直接控制,是以,控制權由程式代碼轉移到了 Spring 容器中,控制權發生了反轉,這就是 Spring 的 IoC 思想。

以往的執行個體建立方法:構造方法(new)、克隆、反射、序列化、動态代理

思考:Javaweb中的servlet對象并沒有手動建立的過程,但是我們可以直接使用其方法,如doGet、doPost等,這是因為tomcat幫助我們執行個體化了對象(容器建立servlet)。

2,入門案例

2.1 在一個工程中建立多個項目 

将多個項目整合到一個工程中,這樣就可以友善的切換多個項目了。

1,建立空工程

11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI

2,通過Maven建立model

11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI

3,項目結構

11-SSM_Spring_IoC與DI

4,再次建立項目Spring02

11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI

5,項目結構

11-SSM_Spring_IoC與DI

2.2 建立執行個體的方法

1,引入依賴

<groupId>com.xxy</groupId>
    <artifactId>Spring01</artifactId>
    <version>1.0-SNAPSHOT</version>    
    <dependencies>
        <!--spring 核心依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <!--測試依賴-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!--編譯插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>      

2,編寫實體類Team

11-SSM_Spring_IoC與DI
package com.xxy.pojo;

public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 預設的構造方法 id="+id+",name="+name+",location="+location);
    }
}      

3,建立測試類

11-SSM_Spring_IoC與DI

4,Spring通過配置建立對象

11-SSM_Spring_IoC與DI
11-SSM_Spring_IoC與DI
<?xml version="1.0" encoding="UTF-8"?>
<!--spring配置檔案
    beans:根标簽
        spring中Java的對象稱為java bean
        spring-beans.xsd是一個限制檔案  限制xml檔案中都能編寫哪些标簽
-->
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--建立對象:聲明bean,告知spring容器建立哪些對象
        一個bean标簽表示一個對象
        id=“對象名”,要求唯一值
        class="完全限定名" spring底層是通過反射方式建立對象,不能寫接口
            相當于com.xxy.pojo.Team team1=new com.xxy.pojo.Team();然後将建立的對象放入spring容器的一個集合Map中
            springMap.put(id,對象)例如 springMap.put(“team1",new Team());
    -->
    <bean id="team1" class="com.xxy.pojo.Team" ></bean>

</beans>      
11-SSM_Spring_IoC與DI

2.3 擷取Spring容器

Spring 提供了兩種 IoC 容器,分别為 BeanFactory 和 ApplicationContext.

1,BeanFactory(new之後不會直接建立執行個體對象,根據id從容器中擷取對象時建立)

BeanFactory 是基礎類型的 IoC 容器,是一個管理 Bean 的工廠,它主要負責初始化各種 Bean,并調用它們的生命周期方法。

BeanFactory 接口有多個實作類,最常見的是org.Springframework.beans.factory.xml.XmlBeanFactory,它是根據 XML 配置檔案中的定義裝配Bean 的。

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(Spring配置檔案 的名稱));      

配置檔案需要寫全路徑,否則會定位失敗。 

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml"));
beanFactory.getBean("team1");//根據ID從IOC容器擷取對象 這時才建立對象      

2,ApplicationContext(new之後直接建立執行個體對象)

ApplicationContext 是 BeanFactory 的子接口,也被稱為應用上下文。它不僅提供了 BeanFactory 的所有功能,還添加了對 i18n(國際化)、資源通路、事件傳播等方面的良好支援。

ApplicationContext 接口有兩個常用的實作類:

ClassPathXmlApplicationContext——常用

該類從類路徑 ClassPath 中尋找指定的 XML 配置檔案(将配置檔案放到resources目錄下,可以直接通過配置檔案名獲得對象),找到并裝載完成 ApplicationContext 的執行個體化工作

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Spring配 置檔案的名稱);      
String springConfig = "application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);      

FileSystemXmlApplicationContext

它與 ClassPathXmlApplicationContext 的差別是:在讀取 Spring 的配置檔案時,FileSystemXmlApplicationContext 不再從類路徑中讀取配置檔案,而是通過參數指定配置檔案的位置,它可以擷取類路徑之外的資源,如“D:\application.xml”。 

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);      
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml");      

2.4 其他常用的api

package com.kkb.test;
import com.kkb.pojo.Team;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;

public class Test01 {
    @Test
    public void test01(){
        //Team team1=new Team();//原有寫法:程式員自己建立對象
        // spring容器建立對象的方式
        String springConfig="application.xml";
        
        //1、擷取spring容器
        //方式1:
       // BeanFactory beanFactory=new XmlBeanFactory(new FileSystemResource("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml"));
       //beanFactory.getBean("team1");//根據ID從IOC容器擷取對象
        //方式2--常用,推薦:
       ApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
       
        //2、從容器中根據ID擷取對象
        Team team1 = (Team) applicationContext.getBean("team1");
        //方式3:
       // ApplicationContext applicationContext=new FileSystemXmlApplicationContext("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml");

        //3、容器中的其他API
        int beanDefinitionCount = applicationContext.getBeanDefinitionCount();
        System.out.println("容器中的對象的個數:"+beanDefinitionCount);
        System.out.println("容器中所有對象的名稱:");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println("\t"+name);
        }

    }
}      

2.5 建立非自定義對象

<!--非自定義對象的建立-->
<bean id="date1" class="java.util.Date"></bean>      
//4、擷取非自定義的對象
Date date1 = (Date) applicationContext.getBean("date1");
System.out.println("擷取非自定義的對象date="+date1);      

4,bean标簽屬性

11-SSM_Spring_IoC與DI

4.1 scope

singleton:單例,預設值,容器啟動完畢之後單例對象就被建立了,而且容器中隻有唯一的一個對象;

prototype:多例,多例的對象是什麼時候使用什麼時候建立,每次擷取的時候都建立新對象;

<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton"></bean>
<bean id="team2" name="team2"  class="com.kkb.pojo.Team" scope="prototype"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
        Team team1 = (Team) applicationContext.getBean("team1");
        Team team11 = (Team) applicationContext.getBean("team1");
        System.out.println(team1);
        System.out.println(team11);
        Team team2 = (Team) applicationContext.getBean("team2");
        Team team22 = (Team) applicationContext.getBean("team2");
        System.out.println(team2);
        System.out.println(team22);
        applicationContext.close();//關閉容器

    }      
11-SSM_Spring_IoC與DI

4.2 lazy-init

true:真懶  擷取對象的時候才建立對象。針對單例模式,因為多例模式本來就是用的時候建立;

false:不懶  立即建立對象,不管是否使用(預設值);

<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton" lazy-init="true"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
    }      
11-SSM_Spring_IoC與DI

4.3 init-method與destroy-method

生命周期相關:

init-method:對象建立完畢之後立即調用的初始化方法(自定義名稱);

destroy-method:spring容器調用關閉方法的時候執行的方法;

public class Team {
    private Integer id;
    private String name;
    public Team() {
        System.out.println("Team - 預設的構造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      
<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton" lazy-init="true" init-method="init" destroy-method="destroy"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        // 這裡使用ClassPathXmlApplicationContext而不是ApplicationContext
        // 因為ApplicationContext沒有定義close方法
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
        Team team1 = (Team) applicationContext.getBean("team1");
        Team team11 = (Team) applicationContext.getBean("team1");
        System.out.println(team1);
        System.out.println(team11);
        Team team2 = (Team) applicationContext.getBean("team2");
        Team team22 = (Team) applicationContext.getBean("team2");
        System.out.println(team2);
        System.out.println(team22);
        applicationContext.close();//關閉容器
    }      

5,建立對象的3種方式

使用預設的構造方法,使用帶參數的構造方法,使用工廠類。

5.1 預設的構造方法

<!--1、通過預設構造方法-->
<bean id="team1" class="com.kbb.pojo.Team"></bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

5.2 帶參數的構造方法 

public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 預設的構造方法 id="+id+",name="+name+",location="+location);
    }

    public Team(Integer id, String name, String location) {
        this.id = id;
        this.name = name;
        this.location = location;
        System.out.println("Team - 帶參數的構造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      
<!-- 2、通過帶參數的構造方法-->
    <bean id="team2" class="com.kbb.pojo.Team">
        <!--name:表示參數的名稱-->
        <constructor-arg name="id" value="1001"/>
        <constructor-arg name="name" value="勇士"/>
        <constructor-arg name="location" value="金州"/>
    </bean>
    <bean id="team3" class="com.kbb.pojo.Team">
        <!--index:表示參數的下标索引-->
        <constructor-arg index="0" value="1002"/>
        <constructor-arg index="1" value="熱火"/>
        <constructor-arg index="2" value="邁阿密"/>
    </bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

5.3 使用工廠方法

 建立工廠類

public class MyFactory {
    /**
     * 執行個體方法
     * @return
     */
    public Team instanceFun(){
        System.out.println("MyFactory------instanceFun");
        return new Team(1003,"湖人","洛杉矶");
    }

    /**
     * 靜态方法
     * @return
     */
    public static Team staticFun(){
        System.out.println("MyFactory------staticFun");
        return new Team(1004,"小牛","達拉斯");
    }

    public static void main(String[] args) {
        Team team1 = MyFactory.staticFun();
        MyFactory factory=new MyFactory();
        Team team = factory.instanceFun();
    }
}      
<!--3、通過工廠方法:
    3.1 靜态方法    Team team1 = MyFactory.staticFun();-->
    <bean id="staticTeam" class="com.kbb.pojo.MyFactory" factory-method="staticFun"></bean>

    <!--3、通過工廠方法:
    3.2 執行個體方法
    MyFactory factory=new MyFactory();
    Team team = factory.instanceFun();-->
    <bean id="factory" class="com.kbb.pojo.MyFactory"></bean>
    <bean id="instanceTeam" factory-bean="factory" factory-method="instanceFun"></bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

6,基于XML的DI

DI—Dependency Injection,即“依賴注入”:是元件之間依賴關系由容器在運作期決定,形象的說,即由容器動态的将某個依賴關系注入到元件之中。比如對象A、B、C均需要D,那麼在D建立之後,可以自動的注入到A、B、C中。

依賴注入的目的并非為軟體系統帶來更多功能,而是為了提升元件重用的頻率,并為系統搭建一個靈活、可擴充的平台。

通過依賴注入機制,我們隻需要通過簡單的配置,而無需任何代碼就可指定目标需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實作。

IoC 是一個概念,是一種思想,其實作方式多種多樣。依賴注入就是其中用的比較多的一種方式。

IoC和DI是同一個概念的不同角度描述。IoC是一種思想,概念,DI是實作它的手段。Spring架構使用依賴注入實作IoC。

Spring 容器是一個超級大工廠,負責建立、管理所有的 Java 對象,這些 Java 對象被稱為 Bean。

Spring 容器管理着容器中 Bean 之間的依賴關系,Spring 使用“依賴注入”的方式來管理 Bean 之間的依賴關系。使用 IoC 實作對象之間的解耦和。

bean 執行個體在調用無參構造器建立對象後,就要對 bean 對象的屬性進行初始化。初始化是由容器自動完成的,稱為注入。

6.1 通過set方法注入

1,設計簡單的dao和service

public class TeamDao {
    public TeamDao() {
        System.out.println("TeamDao ---- 預設的構造方法");
    }
}      
public class TeamService {
//    private TeamDao teamDao = new TeamDao(); // 原先的做法
    private TeamDao teamDao;// 現在隻需要給出聲明,對象的建立交給spring完成

    public TeamService() {
        System.out.println("TeamService---預設構造方法");
    }

    // 必須提供get和set方法!!!
    public TeamDao getTeamDao() {
        return teamDao;
    }

    public void setTeamDao(TeamDao teamDao) {
        this.teamDao = teamDao;
    }
}      

2,編寫spring配置檔案DI.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <bean id="teamService" class="com.xxy.service.TeamService">
        <!--使用set方法注入屬性值-->
        <property name="teamDao" ref="newTeamDao"></property>
    </bean>
</beans>      

3,編寫測試檔案

@Test
    public void test01() {
        String springConfig = "DI.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(springConfig);
    }      
11-SSM_Spring_IoC與DI

6.2 通過構造方法注入

構造注入是指,在構造調用者執行個體的同時,完成被調用者的執行個體化。使用構造器設定依賴關系。

1,修改TeamService,添加帶有參數的構造方法

package com.xxy.service;

import com.xxy.dao.TeamDao;

public class TeamService {

//    private TeamDao teamDao = new TeamDao(); // 原先的做法
    private TeamDao teamDao;// 現在隻需要給出聲明,對象的建立交給spring完成

    public TeamService() {
        System.out.println("TeamService---預設構造方法");
    }

    // 帶有參數的構造方法
    public TeamService(TeamDao teamDao) {
        System.out.println("TeamService---含參構造方法");
        this.teamDao = teamDao;
    }
}      

2,修改spring配置檔案DI.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <bean id="teamService" class="com.xxy.service.TeamService">
        <!--使用set方法注入屬性值-->
        <!--<property name="teamDao" ref="newTeamDao"></property>-->
        <!--使用構造方法注入屬性值-->
        <constructor-arg name="teamDao" ref="newTeamDao"></constructor-arg>
    </bean>
</beans>      
11-SSM_Spring_IoC與DI

6.3 自動注入

對于引用類型屬性的注入,也可不在配置檔案中顯式的注入。

可以通過為标簽設定 autowire 屬性值,為引用類型屬性進行隐式自動注入(預設是不自動注入引用類型屬性)。根據自動注入判斷标準的不同,可以分為兩種:

  • byName:根據名稱自動注入
  • byType: 根據類型自動注入

byName

當配置檔案中被調用者 bean 的 id 值與代碼中調用者 bean 類的屬性名相同時,可使用byName 方式,讓容器自動将被調用者 bean 注入給調用者 bean。

容器是通過調用者的 bean類的屬性名與配置檔案的被調用者 bean 的 id 進行比較而實作自動注入的。

1,修改修改spring配置檔案DI.xml,在調用者的bean标簽中添加autowire屬性

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <!--按名稱自動注入:查找容器中id名與屬性名一緻的對象進行注入-->
    <bean id="teamService" class="com.xxy.service.TeamService" autowire="byName"></bean>
</beans>      

2,運作測試方法

11-SSM_Spring_IoC與DI

byType

使用 byType 方式自動注入,要求:配置檔案中被調用者 bean 的 class 屬性指定的類,要與代碼中調用者 bean 類的某引用類型屬性類型同源。

即要麼相同,要麼有 is-a 關系(子類,或是實作類)。但這樣的同源的被調用 bean 隻能有一個。多于一個,容器就不知該比對哪一個了。

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <!--按類型自動注入:查找容器中類型與屬性類型相同或者符合is-a關系的對象進行注入,但是要求類型相同的對象唯一,否則抛出異常:不知道用哪一個比對-->
    <bean id="teamService" class="com.xxy.service.TeamService" autowire="byType"></bean>
</beans>      

7,基于注解實作IoC

對于 DI 使用注解,将不再需要在 Spring 配置檔案中聲明 bean 執行個體。Spring 中使用注解,需要在原有Spring 運作環境基礎上再做一些改變。

7.1 聲明Bean的注解 @Component

在類上添加注解@Component表示該類建立對象的權限交給Spring容器。注解的value屬性用于指定bean的id值,value可以省略。

@Component 不指定 value 屬性時,bean 的 id 是類名的首字母小寫。

@Component(value="teamDao")
@Component("teamDao")
@Component    // 預設類名首字母小寫      
//@Component 注解辨別在類上,表示對象由Spring容器建立 value屬性表示建立的id值,value可以省略,值也可省略,預設就是類名的首字母小寫
@Component(value="teamDao")
// 相當于xml檔案中的額<bean id="teamDao" class="com.kkb.dao.TeamDao"></bean>
public class TeamDao {
    public void add(){
        System.out.println("TeamDao---- add----");
    }

    public TeamDao() {
        System.out.println("TeamDao ---- 預設的構造放方法");
    }
}      

除此之外,Spring中還提供了其他3個用于建立對象的注解:

  • @Repository:用于dao實作類的的注解;
  • @Service:使用者service實作類的注解;
  • @Controller:用于controller實作類的注解;

這三個注解與@Component 都可以建立對象,但這三個注解還有其他的含義。

  • @Service建立業務層對象,業務層對象可以加入事務功能;
  • @Controller 注解建立的對象可以作為處理器接收使用者的請求。

@Repository,@Service,@Controller 是對@Component 注解的細化,标注不同層的對象。即持久層對象,業務層對象,控制層對象。

@Repository(value="teamDao")
public class TeamDao

@Service("teamService1")
public class TeamService

@Controller
public class TeamController      

7.2 包掃描

需要在 Spring 配置檔案中配置元件掃描器(beans标簽中添加屬性),用于在指定的基本包中掃描注解。如果沒有包掃描,添加的建立對象的注解不生效。

如果要掃描的包有多個,可以有以下方式掃描:

方式1,使用多個context:component-scan指定不同的包路徑

11-SSM_Spring_IoC與DI

方式2,指定 base-package的值使用分隔符

分隔符可以使用逗号(,)分号(;)還可以使用空格,不建議使用空格。

<!--多個包的掃描: 方式2 : base-package中直接聲明要掃描的多個包 ,多個值用逗号,分号或者空格分割,但是空格不推薦-->
<context:component-scan base-package="com.kkb.dao,com.kkb.service,com.kkb.controller"></context:component-scan>      

方式3,base-package是指定到父包名

base-package 的值表是基本包,容器啟動會掃描包及其子包中的注解,當然也會掃描到子包下級的子包。是以 base-package 可以指定一個父包就可以。

但不建議使用頂級的父包,掃描的路徑比較多,導緻容器啟動時間變慢。指定到目标包和合适的。也就是注解所在包全路徑。

<!--多個包的掃描: 方式3: base-package中直接聲明要掃描的多個包的父包-->
<context:component-scan base-package="com.kkb"></context:component-scan>      

8,屬性注入的注解實作

8.1 屬性注入@Vaule

需要在屬性上使用注解@Value,該注解的 value 屬性用于指定要注入的值。

使用該注解完成屬性注入時,類中無需 setter。當然,若屬性有 setter,則也可将其加到 setter 上。

@Component
public class Team {
    @Value("1001")
    private Integer id;
    @Value("湖人隊")
    private String name;
    @Value("洛杉矶")
    private String location;

    // 或者
    // @Value("1001")
    // public void setId(Integer id) {
    //     this.id = id;
    // }
    // @Value("湖人隊")
    // public void setName(String name) {
    //     this.name = name;
    // }
    // @Value("洛杉矶")
    // public void setLocation(String location) {
    //     this.location = location;
    // }

    @Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", location='" + location + '\'' +
                '}';
    }


    public Team() {
        System.out.println("Team - 預設的構造方法 id="+id+",name="+name+",location="+location);
    }

    public Team(Integer id, String name, String location) {
        this.id = id;
        this.name = name;
        this.location = location;
        System.out.println("Team - 帶參數的構造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      

8.2 byType自動注入@Autowired

需要在引用屬性上使用注解@Autowired,該注解預設使用按類型自動裝配 Bean 的方式。使用該注解完成屬性注入時,類中無需 setter。當然,若屬性有 setter,則也可将其加到 setter 上。

8.3 byName自動注入@Autowired和@Qualifier

需要在引用屬性上聯合使用注解@Autowired 與@Qualifier。

  • @Qualifier 的 value 屬性用于指定要比對的 Bean 的 id 值。類中無需 set 方法,也可加到 set 方法上。
  • @Autowired 還有一個屬性 required,預設值為 true,表示當比對失敗後,會終止程式運作。若将其值設定為 false,則比對失敗将被忽略,未比對的屬性值為 null。
@Service("teamService1")
public class TeamService {

    @Autowired(required = false) //自動裝配 預設按照類型裝配
    //@Qualifier("teamDao")//按照名稱自動裝配 需要@Qualifier搭配使用
    private TeamDao teamDao;//=new TeamDao();      

8.4 自動注入@Resource

Spring提供了對 jdk中@Resource注解的支援。@Resource 注解既可以按名稱比對Bean,也可以按類型比對 Bean。預設是按名稱注入。使用該注解,要求 JDK 必須是 6 及以上版本

@Resource 可在屬性上,也可在 set 方法上。

1,byType注入引用類型屬性

@Controller
public class TeamController {
    @Resource(name="teamService1",type = TeamService.class) //JDK版本高于1.6 自動裝配預設按照名稱  但是如果名稱沒有相符的,就按照類型自動裝配
    private TeamService teamService;

    public void add(){
        teamService.add();
        System.out.println("TeamController---- add ----");
    }

    public TeamController() {
        System.out.println("TeamController ---- 預設的構造放方法");
    }
}