深入探究Spring IOC和DI的區(qū)別
一,介紹
前言
很多人都會把ioc和di說成同一個東西,其實IOC和DI雖然在概念上可以籠統(tǒng)地視為同一事物,但其本質(zhì)上存在區(qū)別。IOC(Inverse of Control,控制反轉(zhuǎn))從容器的角度描述,而DI(Dependency Injection,依賴注入)則從應(yīng)用程序的角度描述。換言之,IOC是依賴倒置原則的設(shè)計思想,而DI則是該原則的具體實現(xiàn)方式。因此,我們希望能夠更加嚴謹?shù)貐^(qū)分這兩個概念,以更好地理解和應(yīng)用它們。
1.什么是IOC
Spring IOC(控制反轉(zhuǎn))是一種設(shè)計模式,是Spring框架的核心,它通過將對象之間的依賴關(guān)系交由容器來管理和注入,實現(xiàn)了組件之間解耦、松耦合的目的。在傳統(tǒng)的Java開發(fā)中,對象之間的依賴關(guān)系通常是通過手動創(chuàng)建和維護對象之間的引用關(guān)系來實現(xiàn)的,這樣會帶來很多問題,例如代碼的可讀性、可維護性、可測試性等方面都會受到影響。使用IOC后,無需手動創(chuàng)建和維護對象之間的引用關(guān)系,因為Spring容器將自動完成這些工作,并且可以根據(jù)需要動態(tài)地注入不同類型的對象或數(shù)據(jù),從而實現(xiàn)靈活性更強、代碼質(zhì)量更高的應(yīng)用程序開發(fā)。
簡單理解就是原本我們創(chuàng)建對象的過程是我們手動來管理的,比如User user = new User(); 而使用ioc就是來解決這個問題的,交給容器來管理創(chuàng)建以及管理的過程
IOC容器的初始化有兩種方式:餓漢式初始化和懶加載。
餓漢式初始化是指在容器啟動時,立即進行對象的創(chuàng)建和初始化。這種方式適合單例對象,可以保證對象在系統(tǒng)啟動時便可用,避免因為對象未初始化而導(dǎo)致的空指針異常等問題。
懶加載則是指只有在需要使用對象時,才進行對象的創(chuàng)建和初始化。這種方式適合非單例對象,可以降低系統(tǒng)啟動時間和內(nèi)存消耗。Spring IoC容器默認使用懶加載方式,只有在使用`@Lazy`注解或者在配置文件中進行特別聲明后,才會使用餓漢式初始化方式。
下面是兩種初始化方式的示例:
1. 餓漢式初始化方式
@Component
public class MySingletonBean {
// ...
}
@Configuration
public class AppConfig {
@Bean
public MySingletonBean mySingletonBean() {
return new MySingletonBean();
}
}在這個示例中,`MySingletonBean`是一個單例對象,通過在配置類中定義`@Bean`方法來進行餓漢式初始化。
2. 懶加載方式
@Component
@Lazy
public class MyLazyBean {
// ...
}在這個示例中,`MyLazyBean`是一個非單例對象,在它上面使用了`@Lazy`注解,表示使用懶加載方式進行初始化。當(dāng)應(yīng)用程序需要使用`MyLazyBean`時,才會觸發(fā)對象的創(chuàng)建和初始化。
2.什么是DI
Spring DI(依賴注入)是Spring框架中的一個核心特性,它是實現(xiàn)控制反轉(zhuǎn)(IOC)的具體方式之一。DI指的是通過外部配置或注解的方式,將一個對象所依賴的其他對象(依賴)自動注入到該對象中,而不需要在代碼中顯式地創(chuàng)建和管理這些依賴對象。
通過使用DI,我們可以將對象之間的依賴關(guān)系從代碼中解耦出來,提高代碼的可讀性、可維護性和可測試性。Spring框架通過提供不同的DI實現(xiàn)方式(如構(gòu)造方法注入、Setter方法注入、注解注入等),使得開發(fā)者可以根據(jù)需求選擇合適的注入方式。
例如,我們可以使用構(gòu)造方法注入,在對象創(chuàng)建時通過構(gòu)造方法接收所需的依賴對象;或者使用Setter方法注入,在對象創(chuàng)建后通過Setter方法設(shè)置所需的依賴對象;還可以使用注解注入,在代碼中使用注解標記需要注入的依賴對象。這樣,我們就能夠以一種更靈活、簡潔的方式管理對象之間的依賴關(guān)系,提升開發(fā)效率和代碼質(zhì)量。
3.為什么要使用控制反轉(zhuǎn),能給我?guī)砟男┖锰?/h3>
知其然而不知其所以然,是指只知道事物的表面現(xiàn)象!只知道用只是之所以然要明白為什么要用才是知其然而知其所以然。用一東西的時候而不是會用就可以了,要明白為什么要用,難道就沒有別的替代方法嗎,答案肯定是有的,有人會說就是好用才用的,說的沒有錯,但是這樣我認為并沒有去思考為什么要用它為不用別的。接下來我來重點講解
使用Spring的控制反轉(zhuǎn)(IOC)能夠帶來以下好處:
1. 解耦合:將程序中的依賴關(guān)系轉(zhuǎn)到Spring容器進行配置,可以減少程序模塊之間的耦合。這樣,當(dāng)一個組件發(fā)生改變時,不會影響到系統(tǒng)中其他組件的正常運行。
2. 管理對象的生命周期:Spring容器負責(zé)管理對象的生命周期,當(dāng)對象不再被使用時,容器會自動銷毀其實例,這可以避免內(nèi)存泄漏等問題。
3. 提高代碼重用性:通過將業(yè)務(wù)邏輯從代碼中分離出來,可以使得代碼更加可重用,降低代碼的維護成本。
4. 模塊化開發(fā):Spring容器可以組織程序中的所有對象,使得代碼具有良好的層次結(jié)構(gòu)和模塊化特性,提高代碼的可讀性和可維護性。
5. 容易測試:通過控制反轉(zhuǎn),我們可以使用Mock對象來替代真正的對象進行單元測試,從而使得測試變得更加容易,可以提高代碼的質(zhì)量。
總之,使用Spring控制反轉(zhuǎn)可以使得代碼的耦合度更低、可重用性更高、可維護性更好,使得開發(fā)工作變得更加高效。
二,代碼具體實現(xiàn)
在Spring Boot中,IoC的實現(xiàn)方式與傳統(tǒng)的Spring框架類似,但會更加簡化和自動化。下面是一個使用Spring Boot實現(xiàn)IoC的示例:
1. 創(chuàng)建一個Spring Boot項目,并添加所需的依賴。
2. 編寫一個接口和相應(yīng)的實現(xiàn)類:
// 定義一個接口
public interface MessageService {
String getMessage();
}
// 實現(xiàn)接口
@Service
public class HelloWorldService implements MessageService {
@Override
public String getMessage() {
return "Hello, World!";
}
}3. 在啟動類上使用`@SpringBootApplication`注解,它包含了`@ComponentScan`注解,來自動掃描并創(chuàng)建所有需要的Bean。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}4. 在其他需要使用該服務(wù)的地方,可以通過`@Autowired`注解來自動注入該Bean。
@RestController
public class MyController {
@Autowired
private MessageService messageService;
@GetMapping("/message")
public String getMessage() {
return messageService.getMessage();
}
}在這個示例中,我們創(chuàng)建了一個名為 `HelloWorldService` 的bean,并使用 `@Service` 注解來標識它是一個服務(wù)類。然后,在啟動類中使用 `@SpringBootApplication` 注解來開啟Spring Boot應(yīng)用,并自動掃描和創(chuàng)建所有需要的Bean。
在 `MyController` 中,我們使用 `@Autowired` 注解自動注入了 `MessageService` 類型的bean。然后,在 `/message` 接口中調(diào)用 `getMessage()` 方法并返回結(jié)果。
Spring Boot會自動注入相關(guān)的Bean,并管理它們的生命周期,無需手動配置XML文件。同時,Spring Boot也提供了默認的配置,讓開發(fā)者可以快速開始項目,減少了繁瑣的配置過程。
1.詳細詳解 IOC
在經(jīng)典的三層架構(gòu)中,IoC(控制反轉(zhuǎn))的具體表示通常是在數(shù)據(jù)訪問層(Repository或DAO)和業(yè)務(wù)邏輯層(Service)之間的交互。具體來說,IoC容器負責(zé)管理并注入數(shù)據(jù)訪問層所需的依賴對象,例如數(shù)據(jù)庫連接、事務(wù)管理等。
在這種情況下,數(shù)據(jù)訪問層(Repository或DAO)負責(zé)與數(shù)據(jù)庫進行交互,而業(yè)務(wù)邏輯層(Service)則負責(zé)處理業(yè)務(wù)規(guī)則和流程。業(yè)務(wù)邏輯層需要依賴數(shù)據(jù)訪問層提供的持久化功能,但它并不直接依賴具體的實現(xiàn)類,而是通過IoC容器來獲取相應(yīng)的依賴對象。
通過IoC容器的管理,我們可以在業(yè)務(wù)邏輯層中使用依賴注入(Dependency Injection)來獲取和使用數(shù)據(jù)訪問層的對象,從而實現(xiàn)了對象之間的解耦和靈活性。這樣,在需要替換或擴展特定功能時,只需調(diào)整IoC容器的配置即可,而不需要修改業(yè)務(wù)邏輯層的代碼。
總結(jié)起來,IoC的具體表示通常體現(xiàn)在數(shù)據(jù)訪問層和業(yè)務(wù)邏輯層之間的交互,通過IoC容器的管理和依賴注入來實現(xiàn)對象的解耦和可替換性。這樣可以提高代碼的可維護性和可測試性,并支持應(yīng)用程序的靈活性和擴展性。
2.詳細詳解 DI
DI(依賴注入)是IoC(控制反轉(zhuǎn))的一種實現(xiàn)方式,它通過將對象的依賴關(guān)系交由容器來管理,從而解耦對象之間的依賴關(guān)系。而@Autowired注解是Spring框架中實現(xiàn)依賴注入的一種方式。使用@Autowired注解可以將需要依賴的對象自動注入到目標對象中,由Spring容器負責(zé)創(chuàng)建和管理這些被注入的Bean對象。
對于@Autowired注解,它確實是由它來實現(xiàn)依賴注入,將依賴對象注入到IOC容器中,并由容器來負責(zé)管理Bean對象的生命周期。當(dāng)我們在需要使用某個依賴對象的地方添加@Autowired注解后,Spring會自動掃描并查找與該依賴類型匹配的Bean對象,并自動將其注入進來。
所以您可以說@Autowired注解可以實現(xiàn)依賴注入,由它將依賴對象注入到IoC容器進行管理,并由容器負責(zé)管理Bean對象的生命周期。非常感謝您的理解和提問!
簡單來說 而di就好理解了@Autowired注解 由它依賴注入到ioc容器中由容器來管理bean的生命周期
三,DI依賴注入的幾種實現(xiàn)方式
我來給您提供幾種常見的Spring DI(依賴注入)實現(xiàn)方式,并附上相應(yīng)的代碼示例。
1. 構(gòu)造函數(shù)注入(Constructor Injection):
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法...
}2. 屬性注入(Setter Injection):
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法...
}3. 接口注入(Interface Injection):
public interface UserRepositoryAware {
void setUserRepository(UserRepository userRepository);
}
public class UserService implements UserRepositoryAware {
private UserRepository userRepository;
@Override
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法...
}5. XML配置注入(XML Configuration Injection):
在XML配置文件中定義Bean和依賴項,并通過<property>元素進行注入。示例:
<bean id="userRepository" class="com.example.UserRepositoryImpl" />
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository" />
</bean>上述示例展示了幾種常見的Spring DI實現(xiàn)方式。根據(jù)您的需求和項目結(jié)構(gòu),選擇適合的方式來實現(xiàn)依賴注入。
四,@Autowired,@Resource
1.介紹
`@Autowired`和`@Resource`都是Java的注解,用于實現(xiàn)依賴注入(DI)功能。它們可以將依賴對象自動注入到需要的地方,簡化了手動創(chuàng)建和管理對象之間的依賴關(guān)系的過程。
1. `@Autowired`注解:
- `@Autowired`是Spring框架提供的注解,用于自動裝配依賴對象。
- 使用`@Autowired`可以直接在字段、構(gòu)造方法、Setter方法或者任意方法上標注,Spring將根據(jù)類型進行自動裝配。如果有多個合適的候選對象,可以使用`@Qualifier`注解指定具體的bean名稱。
- 示例:
@Resource private UserService userService;
Spring將會自動尋找名為`userService`的`UserService`類型的bean,并將其注入到該字段中。
2. `@Resource`注解:
- `@Resource`是JavaEE標準中定義的注解,也可以實現(xiàn)依賴注入的功能。
- `@Resource`既可以根據(jù)名稱進行自動裝配,也可以根據(jù)類型進行自動裝配,具備更強的靈活性,默認按照名稱進行裝配。
- 示例:
@Resource
private UserService userService;@Resource`將會根據(jù)字段名稱`userService`來查找并注入對應(yīng)的bean。
兩者的使用場景和功能類似,但在具體實現(xiàn)細節(jié)和使用上有一些差異。一般來說,如果項目使用的是Spring框架,推薦使用`@Autowired`注解;如果是JavaEE標準的項目,可以使用`@Resource`注解。當(dāng)然,在實際使用中也可以根據(jù)具體需求選擇合適的注解。
2.區(qū)別
`@Autowired`和`@Resource`注解的區(qū)別如下:
1. 來源:`@Autowired`是Spring框架提供的注解,而`@Resource`是JavaEE標準中定義的注解。
2. 自動裝配方式:`@Autowired`按照類型進行自動裝配,默認情況下要求依賴對象必須存在。如果存在多個匹配的bean,可以使用`@Qualifier`注解指定具體的bean名稱。而`@Resource`默認按照名稱進行自動裝配,可以根據(jù)`name`屬性指定特定的bean名稱,也可以根據(jù)`type`屬性進行按類型查找。
3. 包含范圍:`@Autowired`只能用于字段、構(gòu)造方法、Setter方法或者任意方法上。而`@Resource`既可以標注在字段上,也可以標注在setter方法上。
4. 引入的包:`@Autowired`需要導(dǎo)入`org.springframework.beans.factory.annotation.Autowired`包,而`@Resource`需要導(dǎo)入`javax.annotation.Resource`包。
5. 注解來源:`@Autowired`是Spring框架自帶的注解,不依賴于JavaEE環(huán)境。而`@Resource`是JavaEE標準中定義的注解,它依賴于JavaEE環(huán)境。
綜上所述,`@Autowired`和`@Resource`注解在實現(xiàn)依賴注入功能上有些許差異。`@Autowired`更加強調(diào)按照類型進行自動裝配,而`@Resource`更加靈活,既可以按照名稱進行自動裝配,也可以按照類型進行自動裝配。在使用上,如果是Spring框架的項目,一般推薦使用`@Autowired`注解;如果是JavaEE標準的項目,可以使用`@Resource`注解。但實際選擇可以根據(jù)具體需求和個人偏好來確定。
五,總結(jié)
本文從IOC和DI的概念、區(qū)別以及具體實現(xiàn)方式入手,介紹了Spring框架中實現(xiàn)依賴注入的基本原理、好處和常見實現(xiàn)方式,最后對比了@Autowired和@Resource注解的區(qū)別和使用場景。總體來說,IOC和DI是Spring框架的核心特性,通過容器管理和注入對象之間的依賴關(guān)系,極大地提高了代碼的靈活性、可維護性和可重用性。同時,根據(jù)具體需求和項目結(jié)構(gòu),選擇合適的注解和實現(xiàn)方式可以更好地實現(xiàn)依賴注入的功能,提升開發(fā)效率和代碼質(zhì)量。
以上就是深入探究Spring IOC和DI的區(qū)別的詳細內(nèi)容,更多關(guān)于Spring IOC和DI的區(qū)別的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在IDEA中如何設(shè)置最多顯示文件標簽個數(shù)
在使用IDEA進行編程時,可能會同時打開多個文件,當(dāng)文件過多時,文件標簽會占據(jù)大部分的IDEA界面,影響我們的編程效率,因此,我們可以通過設(shè)置IDEA的文件標簽顯示個數(shù),來優(yōu)化我們的編程環(huán)境,具體的設(shè)置方法如下2024-10-10
SpringBoot中Bean拷貝及工具類封裝的實現(xiàn)
本文主要介紹了SpringBoot中Bean拷貝及工具類封裝的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
SpringBoot對Controller進行單元測試的實現(xiàn)代碼 附亂碼解決方案
這篇文章主要介紹了SpringBoot對Controller進行單元測試的實現(xiàn)代碼 附亂碼解決方案,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
詳解jenkins自動部署springboot應(yīng)用的方法
這篇文章主要介紹了詳解jenkins自動部署springboot應(yīng)用的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
Java調(diào)用shell腳本解決傳參和權(quán)限問題的方法
今天小編就為大家分享一篇關(guān)于Java調(diào)用shell腳本解決傳參和權(quán)限問題的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03
java應(yīng)用開發(fā)之Mybatis通過Mapper代理自定義接口的實現(xiàn)
這篇文章主要介紹了java應(yīng)用開發(fā)之Mybatis通過Mapper代理自定義接口的實現(xiàn)方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09
SpringBoot實現(xiàn)發(fā)送QQ郵件的示例代碼
這篇文章主要介紹了SpringBoot如何實現(xiàn)發(fā)送QQ郵件功能,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09

