Spring02_基於XML的IOC

来源:https://www.cnblogs.com/codeaction/archive/2020/05/24/12953274.html
-Advertisement-
Play Games

本教程源碼請訪問: "tutorial_demo" 上篇教程我們學習瞭如何使用工廠模式解耦,把對象的創建由程式員交給自定義的工廠類,在這篇教程我們將學到如何使用Spring的IOC解決程式的耦合問題。 一、什麼是IOC IOC:Inversion of Control,控制反轉,將創建對象的權力交給 ...


本教程源碼請訪問:tutorial_demo

上篇教程我們學習瞭如何使用工廠模式解耦,把對象的創建由程式員交給自定義的工廠類,在這篇教程我們將學到如何使用Spring的IOC解決程式的耦合問題。

一、什麼是IOC

IOC:Inversion of Control,控制反轉,將創建對象的權力交給框架。過去創建對象由開發人員通過new的方式創建,有了IOC之後,開發人員不需要new了,只需要從Spring容器(我們可以認為是保存對象的容器)中獲取就可以了,創建對象的控制權發生了轉移,由開發人員轉移給了Spring容器或者說轉移給了Spring框架。這種控制權的轉移,我們稱之為控制反轉。

目的:減少電腦程式的耦合,解除代碼之間的依賴關係。

二、使用IOC(第一個Spring程式)

2.1、創建項目

  1. 在Idea中新建Maven工程;

  2. 工程創建完成後添加相應的坐標。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>ioc</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
        </dependencies>
    </project>
    

2.2、添加相關類

2.2.1、創建持久層介面

package org.codeaction.dao;

public interface IAccountDao {
    void saveAccount();
}

2.2.2、創建持久層介面實現類

package org.codeaction.dao.impl;

import org.codeaction.dao.IAccountDao;

public class AccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("賬戶保存成功");
    }
}

2.2.3、創建業務層介面

package org.codeaction.service;

public interface IAccountService {
    void saveAccount();
}

2.2.4、創建業務層介面實現類

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.dao.impl.AccountDaoImpl;
import org.codeaction.service.IAccountService;

public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao = new AccountDaoImpl();
    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

註意這個類的實現,本教程最後會說明。

2.3、添加XML配置文件

XML文件在resource目錄下。

<?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">
    <!--把對象的創建交給spring來管理-->
    <bean id="accountDao" class="org.codeaction.dao.impl.AccountDaoImpl"></bean>
    <bean id="accountService" class="org.codeaction.service.impl.AccountServiceImpl"></bean>
</beans>

bean標簽作用:配置讓Spring創建對象。預設情況下調用無參構造函數,如果沒有無參構造函數則不能創建成功。

bean標簽屬性

  • id:為對象在容器中提供一個唯一標識,用於獲取對象;
  • class:指定類的全限定類名,用於反射創建對象,預設情況下調用無參構造函數;
  • scope:指定對象的作用範圍,預設是singleton(單例),3.1中會講到;
  • init-method:指定類中的初始化方法名稱;
  • destroy-method:指定類中銷毀方法名稱。

2.4、添加測試類

創建帶有main方法的類,用來進行測試

package org.codeaction.ui;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AccountUI {
    public static void main(String[] args) {
        //1.獲取核心容器對象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //2.根據id獲取Bean對象,這個id是在bean標簽中配置的id
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        IAccountDao accountDao = context.getBean("accountDao", IAccountDao.class);

        System.out.println(accountService);
        System.out.println(accountDao);
        accountService.saveAccount();
    }
}

運行main方法,控制台輸出如下:

org.codeaction.service.impl.AccountServiceImpl@754ba872
org.codeaction.dao.impl.AccountDaoImpl@146ba0ac
賬戶保存成功

2.4.1、BeanFactory和ApplicationContext的區別

  1. BeanFactory是Spring容器中的頂層介面,ApplicationContext是它的子介面;
  2. ApplicationContext只要一讀取配置文件,預設情況下就會創建對象;
  3. BeanFactory什麼時候使用時候創建對象;
  4. ApplicationContext用來創建單例對象,BeanFactory用來創建多例對象。

2.4.2、ApplicationContext介面的實現類

  1. ClassPathXmlApplicationContext可以載入類路徑下的配置文件,要求配置文件必須在類路徑下,不在的話,載入不了。
  2. FileSystemXmlApplicationContext可以載入磁碟任意路徑下的配置文件(必須有訪問許可權)
  3. AnnotationConfigApplicationContext用於讀取註解創建容器的,後面的文章會講到。

三、深入說明

3.1、bean的作用範圍和生命周期

bean的作用範圍由bean標簽中的scope屬性設置,scope屬性可以有如下值:

  • singleton:預設值,單例的;
  • prototype:多例的;
  • request:web項目中,Spring創建一個Bean的對象,將對象存入到request域中;
  • session:web項目中,Spring創建一個Bean的對象,將對象存入到session域中;
  • global session:web項目中,應用在Portlet環境。如果沒有Portlet環境那麼globalSession相當於session。

下麵我們重點說一下singleton和prototype。

3.1.1、singleton

一個應用只有一個對象的實例,它的作用範圍就是整個應用。
生命周期:

  • 對象出生:當應用載入,創建容器時,對象就被創建了;
  • 對象活著:只要容器在,對象一直活著;
  • 對象死亡:當應用卸載,銷毀容器時,對象就被銷毀了。

3.1.2、prototype

每次訪問對象時,都會重新創建對象實例。
生命周期:

  • 對象出生:當使用對象時,創建新的對象實例;
  • 對象活著:只要對象在使用中,就一直活著;
  • 對象死亡:當對象長時間不用時,被Java的垃圾回收器回收了。

3.1.3、案例(代碼基於第一個Spring程式)

3.1.3.1、修改業務層實現類

添加init和destroy方法

package org.codeaction.dao.impl;

import org.codeaction.dao.IAccountDao;

public class AccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("賬戶保存成功");
    }

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

    public void destroy() {
        System.out.println("dao destroy");
    }
}
3.1.3.2、修改持久層實現類

添加init和destroy方法

package org.codeaction.dao.impl;

import org.codeaction.dao.IAccountDao;

public class AccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("賬戶保存成功");
    }

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

    public void destroy() {
        System.out.println("dao destroy");
    }
}
3.1.3.3、修改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">
    <!--把對象的創建交給spring來管理-->
    <!--配置bean時指定初始化和銷毀方法及作用範圍-->
    <bean
            id="accountDao"
            class="org.codeaction.dao.impl.AccountDaoImpl"
            scope="singleton"
            init-method="init"
            destroy-method="destroy"></bean>
    <bean
            id="accountService"
            class="org.codeaction.service.impl.AccountServiceImpl"
            scope="prototype"
            init-method="init"
            destroy-method="destroy"></bean>
</beans>
3.1.3.4、修改測試類
package org.codeaction.ui;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AccountUI {
    public static void main(String[] args) {
        //1.獲取核心容器對象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //2.根據id獲取Bean對象,這個id是在bean標簽中配置的id
        IAccountService accountService1 = (IAccountService) context.getBean("accountService");
        IAccountDao accountDao1 = (IAccountDao) context.getBean("accountDao");
        IAccountService accountService2 = (IAccountService) context.getBean("accountService");
        IAccountDao accountDao2 = (IAccountDao) context.getBean("accountDao");

        System.out.println("accountDao1 == accountDao2 ? " + (accountDao1 == accountDao2));
        System.out.println("accountService1 == accountService2 ? " + (accountService1 == accountService2));
        //容器銷毀
        context.close();
    }
}

單步調試該程式,輸出如下:

dao init
service init
service init
accountDao1 == accountDao2 ? true
accountService1 == accountService2 ? false
dao destroy

通過輸出我們驗證了:

  • singleton的bean對象在容器中只會創建一次,並且創建容器時,就被創建了;
  • prototype的bean對象在容器中能夠創建多次,當使用時,就創建新的對象;
  • singleton的bean對象在容器銷毀時,也被銷毀;
  • prototype的bean對象會被垃圾回收(通過控制台觀察不到)。

3.2、實例化bean的三種方式

3.2.1、三種方式說明

  1. 使用預設無參構造函數;
  2. 使用靜態工廠的方法創建對象;
  3. 使用實例工廠的方法創建對象。

3.2.2、案例(代碼基於第一個Spring程式)

3.2.2.1、創建靜態工廠類
package org.codeaction.factory;

import org.codeaction.service.IAccountService;
import org.codeaction.service.impl.AccountServiceImpl;

/**
 * 模擬一個靜態工廠,創建業務層實現類
 */
public class StaticFactory {
    public static IAccountService  createAccountService() {
        return new AccountServiceImpl();
    }
}
3.2.2.2、創建實例工廠類
package org.codeaction.factory;

import org.codeaction.service.IAccountService;
import org.codeaction.service.impl.AccountServiceImpl;

/**
 * 模擬一個實例工廠,創建業務層實現類
 * 此工廠創建對象,必須現有工廠實例對象,再調用方法
 */
public class InstanceFactory {
    public IAccountService createAccountService(){
        return new AccountServiceImpl();
    }
}
3.2.2.3、修改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">
    <!-- 方式1:使用預設的無參構造方式 -->
    <bean id="accountService1" class="org.codeaction.service.impl.AccountServiceImpl"></bean>

    <!--
        方式2:使用靜態工廠的方法創建對象
        id屬性:指定bean的id,用於從容器中獲取
        class屬性:指定靜態工廠的全限定類名
        factory-method屬性:指定生產對象的靜態方法
    -->
    <bean
	id="accountService2"
        class="org.codeaction.factory.StaticFactory"
        factory-method="createAccountService"></bean>
    <!--
        方式3:使用實例工廠的方法創建對象
        先把工廠的創建交給spring來管理。
        然後在使用工廠的bean來調用裡面的方法。
        factory-bean屬性:用於指定實例工廠bean的id。
        factory-method屬性:用於指定實例工廠中創建對象的方法。
    -->
    <bean id="factory" class="org.codeaction.factory.InstanceFactory"></bean>
    <bean id="accountService3" factory-bean="factory" factory-method="createAccountService"></bean>
</beans>
3.2.2.4、修改測試類
package org.codeaction.ui;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AccountUI {
    public static void main(String[] args) {
        //1.獲取核心容器對象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //2.根據id獲取Bean對象,這個id是在bean標簽中配置的id
        IAccountService accountService1 = (IAccountService) context.getBean("accountService1");
        IAccountService accountService2 = (IAccountService) context.getBean("accountService2");
        IAccountService accountService3 = (IAccountService) context.getBean("accountService3");

        System.out.println(accountService1);
        System.out.println(accountService2);
        System.out.println(accountService3);
    }
}

運行測試類,控制台輸出如下:

org.codeaction.service.impl.AccountServiceImpl@42dafa95
org.codeaction.service.impl.AccountServiceImpl@6500df86
org.codeaction.service.impl.AccountServiceImpl@402a079c

四、目前存在的問題

通過這篇教程的學習,我們對IOC有了一個初步的認識。通過IOC將對象創建的權力交給Spring容器,實現控制權的轉移。本篇教程2.2.4中,創建業務層介面的實現類,裡面的屬性依然使用new對象的方式賦值,在這裡依然沒有解耦,service和dao的對象依然攪在一起,那麼怎麼解決這個問題呢?下一篇我們將學習DI(依賴註入),DI就可以解決目前存在的問題。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 老實說,在實際編程中,訪問者設計模式應用的並不多,至少我是這樣認為的,因為它的主要使用場景並不多。那麼肯定會有人問,訪問者模式的主要使用場景是什麼呢?繼續往下看便知。新聞聯播看多了之後首先要說的是,設計模式中的“訪問者”和現實生活中的“訪問者”其本質是一回事。雖然設計模式中的不太熟悉,但現實生活中的 ...
  • MMU存在的意義 [導讀] 本文從記憶體管理的發展歷程角度層層遞進,介紹MMU的誕生背景,工作機制。而忽略了具體處理器的具體實現細節,將MMU的工作原理從概念上比較清晰的梳理了一遍。 MMU誕生之前: 在傳統的批處理系統如DOS系統,應用程式與操作系統在記憶體中的佈局大致如下圖: 應用程式直接訪問物理內 ...
  • [導讀] 前文描述了棧的基本概念,本文來聊聊堆是怎麼會事兒。RT Thread 在社區廣受歡迎,閱讀了其內核代碼,實現了堆的管理,代碼設計很清晰,可讀性很好。故一方面瞭解RT Thread內核實現,一方面可以弄清楚其堆的內部實現。將學習體會記錄分享,希望對於堆的理解及實現有一個更深入的認知。 註,文 ...
  • 通常大家開發大部分是本地git push 提交,伺服器上git pull 手動更新。git 可以使用webhook實現自動部署。webhook是倉庫平臺的一個鉤子事件,通過hook 鉤子監聽代碼,回調通知(通知地址就是你在各個git倉庫平臺中填寫的webhook地址,一般在你的某個項目倉庫如mypr ...
  • 根據碎片的生命周期,我們知道onAttach()方法首先會被執行,因此在這裡做一些數據初始化的操作,比如調用getNews()方法獲取幾條模擬的新聞數據,以及完成NewsAdapter的創建,然後在onCreateView()方法中載入了news_title_frag佈局,並給新聞列表的ListVi ...
  • 1/ 概述 利用Spring Boot作為基礎框架,Spring Security作為安全框架,WebSocket作為通信框架,實現點對點聊天和群聊天。 2/ 所需依賴 Spring Boot 版本 1.5.3,使用MongoDB存儲數據(非必須),Maven依賴如下: 配置文件內容: 大致程式結構 ...
  • 新開一坑——Elements of Financial Risk Management in Python 用 python 完成 " Elements of Financial Risk Management (Second Edition)" 一書的課後實踐練習,希望年底之前能完成吧。 項目地址 ...
  • 最近開始學Go語言,但是在使用VS Code 編寫Go的時候出現了插件無法下載的問題。最初我的解決辦法也是從github下載再安裝,但是我並不喜歡這種做法,因為我要在多台pc上使用VS Code編寫Go,所以我覺要重覆多次很麻煩,而且插件的安裝也非常麻煩,我曾經一度想放棄學習Go語言,沒錯因為安裝插 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...