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
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...