Spring 的 IoC 和 DI 詳解:從零開始理解與實踐

Spring 的 IoC和 DI 詳解:從零開始理解與實踐

一、IoC(控制反轉)

1、什么是 IoC?

IoC 是一種設計思想,它的核心是將對象的創建和管理權從開發者手中轉移到外部容器(如 Spring 容器)。通過這種方式,開發者不再需要手動創建對象和管理它們之間的依賴關系,而是將這些任務交給 Spring 容器來完成。

舉個例子
在傳統的開發中,如果你需要一個 BookService 來調用 BookDao 的方法,你可能會直接在 BookService 中通過 new BookDao() 創建 BookDao 的實例。這種方式雖然簡單,但會導致代碼的耦合度很高,難以維護和擴展。

而使用 IoC 后,BookDao 的實例會由 Spring 容器創建,并自動注入到 BookService 中。開發者只需關注業務邏輯,無需關心對象的創建和依賴關系。

2、 IoC 的實現原理

IoC 的實現基于 Spring 容器。Spring 容器負責創建對象、管理對象的生命周期以及對象之間的依賴關系。開發者通過配置文件(如 XML 文件)或注解的方式,將類交給 Spring 容器管理。

3、示例代碼

3.1創建類

package dao;public interface BookDao {void save();
}package dao.impl;import dao.BookDao;public class BookDaoImpl implements BookDao {@Overridepublic void save() {System.out.println("BookDao save...");}
}package service;import dao.BookDao;public interface BookService {void save();
}package service.impl;import service.BookService;
import dao.BookDao;public class BookServiceImpl implements BookService {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}@Overridepublic void save() {System.out.println("BookService save...");bookDao.save();}
}

3.2 配置 Spring 容器

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property></bean><bean id="bookDao" class="dao.impl.BookDaoImpl"></bean>
</beans>

3.3 運行程序

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.BookService;public class Main {public static void main(String[] args) {// 創建 Spring 容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 從容器中獲取 BookService 對象BookService bookService = (BookService) applicationContext.getBean("bookService");// 調用 save 方法bookService.save();}
}

4、運行效果

運行程序后,控制臺會輸出以下內容:

BookService save...
BookDao save...

運行效果講解

  • Spring 容器會根據 applicationContext.xml 文件中的配置,創建 BookServiceImplBookDaoImpl 的實例。
  • BookDaoImpl 的實例由 Spring 容器創建并通過 setBookDao 方法注入到 BookServiceImpl 中。

二、DI(依賴注入)

1、什么是 DI?

DI 是 IoC 的一種實現方式,通過外部注入依賴對象,而不是在類內部創建依賴對象。這種方式使得依賴關系更加清晰,便于維護和測試。

2、DI 的實現方式

DI 的實現方式主要有以下幾種:

構造函數注入:通過構造函數傳遞依賴對象。
Setter 注入:通過 Setter 方法注入依賴對象。
字段注入:直接在字段上注入依賴對象(需要使用注解)。

3、示例代碼

3.1 使用 Setter 注入

package service.impl;import dao.BookDao;public class BookServiceImpl implements BookService {private BookDao bookDao;// 通過 Setter 方法注入依賴public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}@Overridepublic void save() {System.out.println("BookService save...");bookDao.save();}
}

3.2 配置 Spring 容器

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property></bean><bean id="bookDao" class="dao.impl.BookDaoImpl"></bean>
</beans>

3.3 運行程序

運行方式與 IoC 示例相同,代碼如下:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.BookService;public class Main {public static void main(String[] args) {// 創建 Spring 容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 從容器中獲取 BookService 對象BookService bookService = (BookService) applicationContext.getBean("bookService");// 調用 save 方法bookService.save();}
}

4 運行效果

運行程序后,控制臺會輸出以下內容:

BookService save...
BookDao save...

運行效果講解

  • BookDaoImpl 的實例由 Spring 容器創建并通過 setBookDao 方法注入到 BookServiceImpl 中。
  • 依賴關系由容器管理,BookServiceImpl 不再直接依賴 BookDaoImpl 的具體實現。

三、Bean 的類型

1、Bean 的基礎類型

1.1 name

可以設置別名,相當于 id 的作用,可以設置多個,后面的 ref 也可以引用 name 中的名字。

<bean id="bookdao" name="dao book se" class="dao.impl.BookDaoImpl"/>

1.2 scope

單例和非單例的設置,具體表現在重新創建時是否會刷新一個新的地址(默認為單例)。

<bean id="bookService" class="service.impl.BookServiceImpl" scope="prototype"/>

2、Bean 的實例化

2.1、構造方法實例化

通過反射的原理(直接通過class類進行)直接進行訪問構造函數,無論是公共還是私有都能強制進行訪問,不能設置實參,會報錯

注:沒有任何改變,系統自帶就有,但不能添加一個有實參的構造,這樣系統不會自動生成會報錯

2.2、靜態方法實例化

factory是一個中轉站,通過改變xml中的獲取方式類獲取到factory中的new方法,本質還是在獲取new中的對象

public static bookdao getOrderDao(){return new bookdaoimpl();
}
方式二:靜態方法實例化<bean id="bookfactory" class="factory.factory1" factory-method="getOrderDao"></bean>

factory-method用于獲取類中的這個方法

2.3、動態工廠

在這里插入圖片描述

方法三:動態方法實例化
<bean id="bookfactory" class="factory.factory2"></bean>
<bean id="dao" factory-method="getOrderDao" factory-bean="bookfactory"></bean>

第一步先實例化對象,也就是第二行代碼

第二部調用實例化的對象, factory-bean獲取第一部的id名

2.4、factorybean

通過接口來實例化一些方法,減少xml中的操作

public class factory3 implements FactoryBean<bookdao>{@Overridepublic boolean isSingleton() {return  true;}@Overridepublic bookdao getObject() throws Exception {return new bookdaoimpl();}@Overridepublic Class<?> getObjectType() {return bookdao.class;}
}

isSingleton()設置是否單例

getObject() 獲取返回對象

Type設置繼承類型

方法四:factoryBean實例化
<bean id="factoryBean" class="factory.factory3"></bean>

3、Bean 的生命周期(兩種方法)

3.1、直接創建

public void service(){System.out.println("book dao save.......");
}
public void init(){System.out.println("init");
}
public void destory(){System.out.println("destory");
}

需要在xml中加參數

<bean id="bookdao" name="dao book se" class="dao.impl.bookdaoimpl" init-method="init" destroy-method="destory"/>

init-method="init"設置初始化

destroy-method="destory"設置銷毀

銷毀的執行需要程序中進行close關閉后才能運行

ClassPathXmlApplicationContext cts = new ClassPathXmlApplicationContext("application.xml");
bookdao bookdao = (bookdao)cts.getBean("bookdao");
bookdao.service();
cts.close();

更改了ApplicationContext為ClassPathXmlApplicationContext

增加了cts.close();

3.2、接口創建實現

public class bookdaoimpl implements dao.bookdao, InitializingBean, DisposableBean {public void service(){System.out.println("book dao save.......");}@Overridepublic void destroy() throws Exception {System.out.println("destory.........");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("init........");}
}

實現了

InitializingBean, DisposableBean 兩個接口

四、注入類型

1、Setter 注入

1.1 引用類型

通過 Setter 方法注入引用類型

public class BookServiceImpl {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}
}
<bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property>
</bean>

ref用于設置這里的名字,name跟類中的名字相同

1.2 簡單類型

通過 Setter 方法注入簡單類型。

public class BookDaoImpl {private String databaseName;private int connectionNum;public void setDatabaseName(String databaseName) {this.databaseName = databaseName;}public void setConnectionNum(int connectionNum) {this.connectionNum = connectionNum;}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><property name="databaseName" value="mysql"></property><property name="connectionNum" value="666"></property>
</bean>

value設置里面的值,沒有順序之分

2、構造器注入

2.1 引用類型

通過構造函數注入引用類型。

public class BookServiceImpl {private BookDao bookDao;public BookServiceImpl(BookDao bookDao) {this.bookDao = bookDao;}
}
<bean id="bookService" class="service.impl.BookServiceImpl"><constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
</bean>

2.2 簡單類型

通過構造函數注入簡單類型。

public class BookDaoImpl {private String databaseName;private int connectionNum;public BookDaoImpl(String databaseName, int connectionNum) {this.databaseName = databaseName;this.connectionNum = connectionNum;}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><constructor-arg name="databaseName" value="mysql"></constructor-arg><constructor-arg name="connectionNum" value="666"></constructor-arg>
</bean>

2.3命名的其他操作

name的命名可能耦合度過高

1、采取type=“” 類型來進行確定

2、采取index=""位置來進行確定

在這里插入圖片描述

3、自動注入

在xml中進行配置直接進行注入

<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire屬性:開啟自動裝配,通常使用按類型裝配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

autowire一般情況使用bytype按類型

當有兩個名字的情況進行按名字,名字取決于dao中的private類型

注意:setter類型不能夠忘記,不然會報錯
在這里插入圖片描述

4、集合注入

通過 XML 配置注入集合類型。

public class BookDaoImpl {private int[] array;private List<String> list;private Set<String> set;private Map<String, String> map;private Properties properties;// Getter 和 Setter 方法
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><property name="array"><array><value>100</value><value>200</value><value>300</value></array></property><property name="list"><list><value>itcast</value><value>itheima</value></list></property><property name="set"><set><value>itcast</value><value>itheima</value></set></property><property name="map"><map><entry key="country" value="china"/><entry key="province" value="henan"/></map></property><property name="properties"><props><prop key="country">china</prop><prop key="province">henan</prop></props></property>
</bean>

五、總結

IoC 和 DI 是 Spring 框架的核心概念,它們的主要作用是降低代碼的耦合度,提高代碼的靈活性和可維護性。

  • IoC:通過將對象的創建和管理交給 Spring 容器,開發者只需關注業務邏輯。
  • DI:通過依賴注入的方式,使得依賴關系更加清晰,便于維護和測試。

在實際開發中,合理使用 IoC 和 DI 能夠顯著提高代碼的質量和可維護性。希望這篇博客能夠幫助你更好地理解和應用 Spring 的 IoC 和 DI!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76265.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76265.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76265.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM基礎架構:內存模型×Class文件結構×核心原理剖析

&#x1f680;前言 “為什么你的Java程序總在半夜OOM崩潰&#xff1f;為什么某些代碼性能突然下降&#xff1f;一切問題的答案都在JVM里&#xff01; 作為Java開發者&#xff0c;如果你&#xff1a; 對OutOfMemoryError束手無策看不懂GC日志里的神秘數字好奇.class文件如何變…

.DS_Store文件泄露、.git目錄泄露、.svn目錄泄露漏洞利用工具

&#x1f409;工具介紹 一款圖形化的 .DS_Store文件泄露、.git目錄泄露、.svn目錄泄露漏洞利用工具。 &#x1f3af;使用 本工具使用Python3 PyQt5開發&#xff0c;在開始使用前&#xff0c;請確保已經安裝了相關模塊&#xff1a; pip3 install -r requirements.txt -i ht…

為何在 FastAPI 中需要允許跨域訪問(CORS)?(Grok3 回答)

prompt: 你是一個文筆流暢、專業性極強的技術博客博主&#xff0c;你將結合具體的例子和實際代碼解釋寫一篇為何后端選擇fastapi框架時&#xff0c;需要允許跨域訪問。 為何在 FastAPI 中需要允許跨域訪問&#xff08;CORS&#xff09;&#xff1f; 在現代 Web 開發中&#xf…

JDK8前后日期(計算兩個日期時間差-高考倒計時)

JDK8之前日期、時間 Date SimpleDateFormat Calender JDK8開始日期、時間 LocalDate/LocalTime/LocalDateTime ZoneId/ZoneDateTIme Instant-時間毫秒值 DateTimeFormatter Duration/Period

Gerapy二次開發:用戶管理專欄主頁面開發

用戶管理專欄主頁面開發 寫在前面用戶權限控制用戶列表接口設計主頁面開發前端account/Index.vuelangs/zh.jsstore.js后端Paginator概述基本用法代碼示例屬性與方法urls.pyviews.py運行效果總結歡迎加入Gerapy二次開發教程專欄! 本專欄專為新手開發者精心策劃了一系列內容,旨…

關于Spring MVC中傳遞數組參數的詳細說明,包括如何通過逗號分隔的字符串自動轉換為數組,以及具體的代碼示例和總結表格

以下是關于Spring MVC中傳遞數組參數的詳細說明&#xff0c;包括如何通過逗號分隔的字符串自動轉換為數組&#xff0c;以及具體的代碼示例和總結表格&#xff1a; 1. 核心機制 Spring MVC支持直接通過逗號分隔的字符串將請求參數自動轉換為數組&#xff08;String[]、int[]等&…

大模型學習七:?小米8閑置,直接安裝ubuntu,并安裝VNC遠程連接手機,使勁造

一、說明 對于咱們技術人來說&#xff0c;就沒有閑的蛋疼的時候&#xff0c;那不是現在機會來了 二、刷機器準備 1、申請解鎖手機 申請解鎖小米手機https://www.miui.com/unlock/download.html 下載工具&#xff0c;安裝下面的步驟來&#xff0c;官網不欺人吧 打開開發者工…

repo安裝配置

1.安裝屬性 以下配置方式二選一進行安裝 1.1全局級別配置 1. 安裝 repo 工具 在終端中輸入以下命令以下載 repo 工具&#xff1a; curl https://storage.googleapis.com/git-repo-downloads/repo > /usr/bin/repo chmod ax /usr/bin/repo 1.2用戶級別配置 1. 安裝 r…

Go 語言數據類型

Go 語言數據類型 概述 Go 語言(也稱為 Golang)是一種靜態強類型、編譯型、并發型、具有垃圾回收功能的編程語言。自2009年發布以來,Go 語言因其簡潔的語法、高效的執行速度和強大的并發處理能力而廣受歡迎。本文將詳細介紹 Go 語言中的數據類型,幫助讀者更好地理解和掌握…

C# 看門狗策略實現

using System; using System.Threading;public class Watchdog {private Timer _timer;private volatile bool _isTaskAlive;private readonly object _lock new object();private const int CheckInterval 5000; // 5秒檢測一次private const int TimeoutThreshold 10000; …

Font Awesome Web 應用圖標

1. 什么是 Font Awesome Web 應用圖標 Font Awesome Web 應用圖標是 Font Awesome 圖標庫中與 Web 開發相關的子集&#xff0c;適用于界面設計、用戶交互和功能標識。 定義與作用 定義&#xff1a;這些圖標包括導航&#xff08;如“主頁”&#xff09;、操作&#xff08;如“…

如何實現H5端對接釘釘登錄并優雅擴展其他平臺

如何實現H5端對接釘釘登錄并優雅擴展其他平臺 釘釘H5登錄邏輯后端代碼如何實現&#xff1f;本次采用策略模式工廠方式進行定義接口確定會使用的基本鑒權步驟具體邏輯類進行實現采用注冊表模式&#xff08;Registry Pattern&#xff09;抽象工廠進行基本邏輯定義具體工廠進行對接…

STM32F103C8T6單片機開發:簡單說說單片機的外部GPIO中斷(標準庫)

目錄 前言 如何使用STM32F1系列的標準庫完成外部中斷的抽象 初始化我們的GPIO為輸入的一個模式 初識GPIO復用&#xff0c;開啟GPIO的復用功能時鐘 GPIO_EXTILineConfig和EXTI_Init配置外部中斷參數 插入一個小知識——如何正確的配置結構體&#xff1f; 初始化中斷&#…

【自然語言處理】深度學習中文本分類實現

文本分類是NLP中最基礎也是應用最廣泛的任務之一&#xff0c;從無用的郵件過濾到情感分析&#xff0c;從新聞分類到智能客服&#xff0c;都離不開高效準確的文本分類技術。本文將帶您全面了解文本分類的技術演進&#xff0c;從傳統機器學習到深度學習&#xff0c;手把手實現一套…

Java Lambda與方法引用:函數式編程的顛覆性實踐

在Java 8引入Lambda表達式和方法引用后&#xff0c;函數式編程范式徹底改變了Java開發者的編碼習慣。本文將通過實戰案例和深度性能分析&#xff0c;揭示如何在新項目中優雅運用這些特性&#xff0c;同時提供傳統代碼與函數式代碼的對比優化方案。 文章目錄 一、Lambda表達式&a…

劍指offer經典題目(三)

目錄 動態規劃入門 二進制運算 鏈表相關 動態規劃入門 題目1&#xff1a;一只青蛙一次可以跳上1級臺階&#xff0c;也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法&#xff08;先后次序不同算 不同的結果&#xff09;。OJ地址 簡單圖示如下。 題目分析&#…

【每日隨筆】叢林法則 ( 弱肉強食 | 適者生存 | 資源有限稀缺 | 沒有道德約束 | 自發性與無序性 | 叢林法則映射 - 資源分配 與 社會分層 )

文章目錄 一、叢林法則1、弱肉強食2、適者生存3、資源有限稀缺4、沒有道德約束5、自發性與無序性6、叢林法則映射 - 資源分配 與 社會分層 一、叢林法則 叢林法則 是 在 資源有限 的環境中 , 競爭 是生存的基礎 , 弱肉強食 , 適者生存 , 且過程 不受道德約束 ; 叢林法則 在 自…

【含文檔+PPT+源碼】基于小程序的智能停車管理系統設計與開發

項目視頻介紹&#xff1a; 畢業作品基于小程序的智能停車管理系統設計與開發 課程簡介&#xff1a; 本課程演示的是一款基于小程序的智能停車管理系統設計與開發&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;…

Navicat連接遠程PostGreSQL失敗

問題描述 使用本地Navicat連接Windows遠程服務器上部署的PostGreSQL數據庫時,出現以下錯誤: 解決方案 出現以上報錯信息,是因為PostGreSQL數據庫服務尚未設置允許客戶端建立遠程連接。可做如下配置, 1. 找到PostGreSQL數據庫安裝目錄下的data子文件夾,重點關注:postgres…

【Linux】jumpserver開源堡壘機部署

JumpServer 安裝部署指南 本文檔詳細記錄了 JumpServer 安裝部署的過程、核心腳本功能說明以及后續管理使用提示&#xff0c;方便運維人員快速查閱和二次安裝。 1. 前提條件 操作系統要求&#xff1a; 僅支持 Linux 系統&#xff0c;不支持 Darwin&#xff08;macOS&#xff0…